contentSync - синхронизация контента прода и дева для MODX Revolution
Привет, я снова тут!
Одна из дегенеративных особенностей MODX — хранить все в базе. Кони, люди, контент — все хранится в базе.
Еще более дегенеративная особенность — MODX учит вас хранить все в ресурсах и это не сказать что правильная логика.
Часто возникает ситуация, что тестовая версия сайта начинает плотно отставать по контенту от продакшена и необходимо как-то синхронизировать изменения.
Я придумал решение, которое отчасти решает мою задачу и потребность. Если решение вам понравится — я упакую все в пакет и выложу в бесплатный доступ.
Для начала создадим папку для хранения нашего json чуда. Я выбрал core/components/contentSync. Создаем эту папку.
Далее — необходимо сделать так, чтобы менеджеры при изменении ресурсов генерили нам наши объекты. Самый простой способ — создать плагинчик на событие OnDocFormSave
Листинг прилагаю:
Итак, плагин мы добавили, менеджер шустрит по сайту и создает элементы. Рано или поздно мы обнаружим целый склад файлов json и папке созданной выше.
Переносим в эту же папку на нашем dev сайте.
Далее — необходимо реализовать алгоритм который будет обратно создавать объекты. Учтем что объекты нужно обновлять и создавать. Конечно неплохо бы еще удалять но я распишу ниже почему я не сделал это прямо сейчас.
В качестве реализации и просто создал внешний от MODX файл, аля коннектора. Опять же, решение исключительно для демонстрации. Все же, рекомендую файл запускать позже из-под CLI, ибо если ресурсов сотни\тысячи то лимита сервера на выполнения может не хватить (не всегда можно переопределять данные в скрипте).
Файл sync.php в корне. Его листинг:
Подумаем о светлом будущем и будем писать названия классов через ::class. Вдруг этот компонент нужно будет переводить на тройку и этим действием мы выключим кучу deprecated ошибок в логах. В двойке данная реализация тоже работает.
Последний этап — запуск скрипта. Если вы увидите в консоли какие-то ошибки, следовательно какой-то ресурс обновится не смог. Обратите внимание на ошибку.
Вот и вся история с хроникой.
Итак, немного послесловия. Почему данная реализация не самая классная?
Ваши донаты — абсолютно честно пойдут на пиво.
Спасибо!
Разработка проспонсирована компанией «Тузик» zoosklad.by -> Оптовая продажа товаров для животных в Республике Беларусь
P.S Фича реквест для @Василий Наумкин
Очень было бы круто, что если я указываю определенный тег, то ниже код парсится как markdown текст. Я часто готовлю любые тексты в Bear для macOS и в нем архиудобно, но потом приходится переводить текст в теги сайта. Если это не слишком долго и сложно, может стоит рассмотреть к реализации?
Одна из дегенеративных особенностей MODX — хранить все в базе. Кони, люди, контент — все хранится в базе.
Еще более дегенеративная особенность — MODX учит вас хранить все в ресурсах и это не сказать что правильная логика.
Часто возникает ситуация, что тестовая версия сайта начинает плотно отставать по контенту от продакшена и необходимо как-то синхронизировать изменения.
Я придумал решение, которое отчасти решает мою задачу и потребность. Если решение вам понравится — я упакую все в пакет и выложу в бесплатный доступ.
Дисклеймер: Это прототип, грубо говоря proof of concept. Код — не финальный. Да и я — не гений.Суть в том, что все объекты зависимые от modResource можно паковать в JSON объекты и переносить их от сайта к сайту, делая обратное воспроизведение.
> Ниже — буду указаны базовые действия чтобы воспроизвести все руками. Код, который попадет в компонент — скорее всего будет другой.
Для начала создадим папку для хранения нашего json чуда. Я выбрал core/components/contentSync. Создаем эту папку.
Далее — необходимо сделать так, чтобы менеджеры при изменении ресурсов генерили нам наши объекты. Самый простой способ — создать плагинчик на событие OnDocFormSave
Листинг прилагаю:
<?php
if ($modx->event->name == 'OnDocFormSave'){
if (is_object($resource)){
$element = $resource->toJson();
if (!empty($element)){
if (file_put_contents(MODX_CORE_PATH.'components/contentSync/'.$resource->get('id').'.json', $element) === FALSE){
$modx->log(1,'Ошибка'); //Укажите адекватный и понятный для вас код ошибки
return 0;
}
}
}
}Собственно — тут все понятно. Делаем проверки, чтобы не попала никакая дичь в нашу папку. Классно, что у xPDO есть методы toJson и fromJson. Самую малость облегчает нам жизнь.Итак, плагин мы добавили, менеджер шустрит по сайту и создает элементы. Рано или поздно мы обнаружим целый склад файлов json и папке созданной выше.
Переносим в эту же папку на нашем dev сайте.
Далее — необходимо реализовать алгоритм который будет обратно создавать объекты. Учтем что объекты нужно обновлять и создавать. Конечно неплохо бы еще удалять но я распишу ниже почему я не сделал это прямо сейчас.
В качестве реализации и просто создал внешний от MODX файл, аля коннектора. Опять же, решение исключительно для демонстрации. Все же, рекомендую файл запускать позже из-под CLI, ибо если ресурсов сотни\тысячи то лимита сервера на выполнения может не хватить (не всегда можно переопределять данные в скрипте).
Файл sync.php в корне. Его листинг:
<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);
header('Content-type: text/html; charset=utf-8');
set_time_limit(0);
ini_set('memory_limit', '4048M');
ini_set('max_execution_time', '0');
define('MODX_API_MODE', true);
require 'index.php';
$modx->getService('error','error.modError');
$modx->setLogLevel(modX::LOG_LEVEL_INFO);
$response = $modx->runProcessor('security/login', array('username' => 's21494', 'password' => 'm9XK60bX9kq1'));
if ($response->isError()) {
$modx->log(modX::LOG_LEVEL_ERROR, $response->getMessage());
echo 'Ошибка авторизации';
die();
}
$modx->initialize('mgr');
$path = MODX_CORE_PATH.'/components/contentSync/';
$collection = [];
if (is_dir($path)){
if ($folder = opendir($path)){
while (false !== ($entry = readdir($folder))) {
if (strpos($entry,'.json')){
array_push($collection,$entry);
}
}
}
}
closedir($folder);
if (!empty($collection)){
foreach ($collection as $element){
$json_data = file_get_contents($path.$element);
$resource = $modx->getObject(modResource::class,['id' => preg_replace('/\.\w+$/', '', $element)]);
if (is_object($resource)){
$response = $modx->runProcessor('resource/update', $modx->fromJson($json_data));
if ($response->isError()) {
print_r($modx->error->failure($response->getMessage()));
}
} else {
$response = $modx->runProcessor('resource/create', $modx->fromJson($json_data));
if ($response->isError()) {
print_r($modx->error->failure($response->getMessage()));
}
}
}
}
else {
echo 'Коллекция элементов пуста';
}Обратите внимание — вам нужно авторизоваться в контексте mgr, для этого необходимо ввести данные пользователя, который обладает правами на создание и обновление ресурсов, а так же доступ в админка, собственно. Подумаем о светлом будущем и будем писать названия классов через ::class. Вдруг этот компонент нужно будет переводить на тройку и этим действием мы выключим кучу deprecated ошибок в логах. В двойке данная реализация тоже работает.
Последний этап — запуск скрипта. Если вы увидите в консоли какие-то ошибки, следовательно какой-то ресурс обновится не смог. Обратите внимание на ошибку.
Вот и вся история с хроникой.
Итак, немного послесловия. Почему данная реализация не самая классная?
- Нельзя передать id при создании элемента. Следовательно нужно полное совпадение текущих id на сайтах. Если менеджер удаляет ресурсы без возврата — инкремент в базе сместит все айдишники и это крайне грустно. В качестве финального решения возможно стоит использовать alias. В одном и том же контексте двух элементов с одним alias быть не может, а следовательно его можно использовать как ключ.
- Не синхронизируются элементы которые не являются ресурсами. А следовательно условный справочник «Бренды» в minishop2 останется не актуальный. Возможно, стоит дёргать всех наследников xPDOObject и xpdoSimpleObject используя getCollectionGraph
Ваши донаты — абсолютно честно пойдут на пиво.
Спасибо!
Разработка проспонсирована компанией «Тузик» zoosklad.by -> Оптовая продажа товаров для животных в Республике Беларусь
P.S Фича реквест для @Василий Наумкин
Очень было бы круто, что если я указываю определенный тег, то ниже код парсится как markdown текст. Я часто готовлю любые тексты в Bear для macOS и в нем архиудобно, но потом приходится переводить текст в теги сайта. Если это не слишком долго и сложно, может стоит рассмотреть к реализации?
Комментарии: 39
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
markdowntohtml.com
+1 В карму)
Плохо, что MODX не учит, что ресурс — это эндпойнт.
Изначально MODX имел тип платформы CMS/CMF, что заложило более гибкую модель разработки. То есть проект начинаем со стандартных задач, использую объектную модель MODX и в какой-то момент роста проекта модель расширяется появляться кастомные таблицы, появляются свои классы и кастомизируется бек-энд часть MODX. Вот пример как MODX LLC видело использование своей платформы Связи с этим комментарий Павла Бигеля даже аргументом Сергею Шлокову нельзя назвать. Так как он не противоречит вышесказанному.
Но в какой-то момент MODX REVO обрусел, появилось экосистема базирующиеся на трех ресурсах modx.pro, modstore.pro, modhost.pro и тема гибридности начала транспонироваться в CMS. Cвоими особенностями недостатками минусами и плюсами. И если смотреть с точки зрения призмы сообщества modx.pro точки зрения Павла Бигеля уместна.
miniShop2 делает так же, но это всё равно ресурсы — они так же попадают в кэш ресурсов сайта и так же приведут к тормозам, если их будет много.
Принципиальной разницы я не вижу.
Стало быть, храниться в нём будут обычные ресурсы. Вот и подтверждение в процессоре publish на строке 32
Дальше мне копать исходники лень, но вроде и так всё понятно.
А как только ты захочешь написать популярное дополнение, которое будет хранить свой контент не в ресурсах, тебе сразу придётся написать еще кучу сниппетов для генерации по ним меню, карты сайта, хлебных крошек и т.д.
То есть, создать параллельную инфраструктуру сайта для твоего допа. Которую людям надо будет осваивать вместо обычной.
Я вот до сих пор этого не сделал, хотя одно время всерьёз над этим подумывал, как вектор для развития miniShop.
Нет, никто так не делает во фреймворках, там ты всё пишешь под себя.
Именно поэтому я и доказываю тебе, что в ресурсы в MODX — они именно что для контента. Это ограничивает систему, но делает её удобной для новичков и небольших сайтов.
Использование modResource в MODX — это единственно верный путь для хранения пользовательского контента в 99% использования системы. А если кому-то это не подходит, нужно поискать другую систему, таков мой вывод.
А сейчас, по факту, пока я буду расширять класс modResource под каждую свою модель я на том же ларавеле за это время половину админки напишу
А это примерно как сравнивать «запорожец», «формулу 1», «самолет», и «круизный лайнер» — они выполняют одну задачу, перевозят людей. Но делают он очень по-разному. IT рынок безграничен. И решений очень много. Я думаю, с этим согласен каждый.
«CMS — для быстрого создания сайта, но процесс расширения ресурсов вручную настолько времязатратен в modx что за то же время можно половину своей админки на Laravel написать», подразумевая что написать свою админку в laravel далеко не быстрая задача, и такие времязатраты в CMS не допустимы и именно по этому modx именно «приучает» хранить все в ресурсах и не делать свои модели под разные сущности, а унифицировать их через id шаблона, что откровенно очень плохая практика
А вообще для меня выглядит странно — принять руководство по расширения базового класса инструкцией к использованию ресурсов как хранилище контента сайта.
А зачем? Есть уже готовые пакеты. В крайнем случае, можно по аналогии сделать свой пакет из заготовки modExtra.
И на ларавел ты не напишешь быстрее аналог дерева ресурсов. А на твоё возражение, что ты и не будешь его писать, отвечу — и в MODX не надо всё пихать в дерево ресурсов.
П.С. Это конечно моё мнение и оно может отличаться от твоего. Это не значит, что оно правильное или нет. Просто нет одного правильного решения. Каждый пилит код как умеет.
И по умолчанию в админке создаётся именно modDocument. Это не для хранения контента? И все сниппеты заточены именно под вывод этих документов, и для построения по ним навигации. Да и поля у этих документов как-бы намекают: published, pub_date, hide_menu, link_attributes и т.д.
Что бы там Джейсон себе не фантазировал, но как только разработчик доходит до мысли, что нужные ему данные проще хранить в своих таблицах, ему резко перестают быть нужны ТВ, шаблоны, чанки и сам MODX.
Потому что он переходит работать на фреймворки, которые создают таблицы и модели гораздо проще и быстрее.
100%. Многие бывшие модиксеры из этого сообщества это подтвердят.
Слишком большой объём работы и непонятный выхлоп. Экономически не выгодно.
Если ты перетаскиваешь весь контент в другие таблицы, то какой-нибудь GoogleSiteMap для них карту сайта не построит, а mSearch2 их для поиска не проиндексирует.
Сегодня есть pdoTools, и с его помощью можно выводить данные из любых таблиц, для которых есть схема, но опять же, все его родные сниппеты заточены именно под ресурсы. Например, в pdoResources прописана сортировка именно по publishedon, которого может не быть в другой таблице. А pdoMenu использует карту ресурсов в modX::getParentIds для построения меню.
У меня тоже.
Но это у меня и тебя, в наших непубличных проектах.
А теперь представь себе условный miniShop3, который хранит миллионы товаров в своих собственных таблицах. К нему нужно будет поставить и полный набор всех сниппетов для вывода этих товаров, генерации меню, хлебных крошек и т.д.
Как оно, сильно больше Collections будет? Одну документацию писать замучаешься, а потом баги отлавливать и править.
Говорю же, я много об этом думал и пришёл к выводу, что делать подобное не стоит. Ну а если и делать, то как отдельную независимую либу, которую потом интегрировать с MODX.
Собственно, как Андрей Чирко уже сделал с Shopkeeper 4 — и что-то большого успеха на рынке MODX у такого решения не видать.
Я бы с радостью посмотрел на эти готовые пакеты, либо мы говорим о разном, либо ты не видел тот же билдер в октябре и не представляешь о чем я говорю (кстати билдер, это первое что приводят в пример защитники октября, и к сожалению — это единственное его преимущество, все еще возникает вопрос зачем?)
Обязательной не является, но было бы гораздо удобнее если бы являлась и была удобно реализована)
Но да ладно, это все действительно имхо
Про Gitify есть где-нибудь хорошее описание? На русском, текстовое и актуальное :-)?
У меня такая задача. На модкс частично перенесена система управления производством (Первоначально сделанная на Excel директором. Но excel тупит на больших объемах данных и синхронизация разных книг еще тот геморой). Регулярно на сайте что-то меняется. Сейчас, чтобы не мешать рабочему процессу фирмы, сделали тестовую копию сайта. Теперь желательно сделать так чтобы ее можно было быстро синхронизировать с рабочим сайтом.
Нужно чтоб с тестового сайта переносились изменения всех ресурсов, копировались все измененные файлы компонентов и переносилась структура таблиц компонентов без изменения данных. Еще таблицы с настройками желательно настроить чтоб копировались, но это можно и ручками.
Если тут спецы по Gitify есть, подскажите пожалуйста, это можно сделать? И где смотреть как такое организовать?