Cyrax_02

Cyrax_02

С нами с 04 августа 2013; Место в рейтинге пользователей: #250
Cyrax_02
17 января 2015, 02:32
0
1. От Сергея modx.pro/help/4600/#comment-33447
OnDocFormRender не выполняется при сохранении значения, только при перезагрузке страницы (вполне логично).

Именно поэтому, если в период между загрузкой страницы ресурса и сохранением ресурса сессия истечёт, то при сохранении ресурса (будет запрошена авторизация) в массиве $_SESSION значение discount_before установлено не будет.

Более того, если другой пользователь (с другой сессией) изменит значение скидки в период между загрузкой страницы ресурса и сохранением ресурса, то в OnDocFormRender будут получены старые значения (имевшие место в момент открытия страницы ресурса). Впрочем, в вашем случае, к проблемам это не приведёт, но во многих других задачах, где требуется обязательно получать актуальные на текущий момент значения, этот факт делает данный способ получения старых (исходных) значений неприменимым.

2. От Василия modx.pro/help/4600/#comment-33439
$_POST тоже приходит только при перезагрузке страницы + приходится пользоваться переменной сессии.

В массиве $_POST данные передаются именно в момент сохранения ресурса (скрипт сохранения вызывает коннектор путём отправки самостоятельного http-запроса к серверу).

Для получения старых (исходных) значений необходимо:
а) в OnBeforeDocFormSave — метод getTVValue()
б) в OnDocFormSave — только через ранее «запомненные» значения (например, через переменные сессии)

В любом случае, как я уже говорил, новых значений в POST-параметрах запроса не будет, если ресурс сохраняется из собственного кода. Кроме того, от версии к версии формат передаваемых в $_POST данных может меняться, поскольку эти данные предназначены исключительно для внутренних нужд modx (для коннекторов).
Cyrax_02
17 января 2015, 02:06
0
3. От Cyrax_02 modx.pro/help/4600/#comment-33448 Не смог добраться до массива data.
В итоге остановился на варианте №1. Указанные ограничения победить пока не удалось.

Навскидку могу предположить, что:
а) ты его «искал» в тот момент, когда у тебя плагин не был подписан на событие OnDocFormSave и (или) OnDocFormRender. Массив $data передаётся только обработчику OnBeforeDocFormSave
б) получить к нему доступ ты пытался в разделе case 'OnDocFormRender' или case 'OnDocFormSave' оператора switch. С массивом $data нужно работать в case 'OnBeforeDocFormSave'

Ещё раз по порядку:
1) Подписываешь плагин на событие OnBeforeDocFormSave
2) В плагине в разделе case 'OnBeforeDocFormSave' пишешь:
$modx->log(modX::LOG_LEVEL_ERROR, print_r($data, true));
3) Загружаешь страницу (именно ту, которая вызывает плагин)
4) Смотришь логи modx: там увидишь все НОВЫЕ стандартные и ТВ-параметры, которые содержит массив $data. Также увидишь их ключи (как к ним обращаться).

События OnBefore...FormSave генерируются до физического сохранения новых значений и только в обработчиках этого события можно одновременно получить доступ и к старым значениям полей, и к новым. Именно для этого в OnBefore...FormSave и передаётся массив новых значений $data, которые будут физически сохранены после этого события.

P.S. У варианта OnBeforeDocFormSave + массив data + getTVValue пока не вижу никаких ограничений. Полная свобода.
Cyrax_02
15 января 2015, 11:39
1
0
Но вот как получить ТВ по событию OnBeforeDocFormSave (кроме предложенного выше решения)?

В OnBeforeDocFormSave новые (сохраняемые) значения TV можно получить следующими способами:
1) Из массива $_POST (как указал Василий). Но этот вариант работает только при вызове коннекторов (сохранение ресурса в админке). Если процессор вызывается из собственного кода, то никаких параметров в запросе не будет.

2) Из массива data, который также передаётся плагину (не задокументирован). В этом массиве лежат все новые (сохраняемые) параметры — и стандартные, и ТВ. Ключ стандартного параметра = имени параметра, ключ ТВ = tvID.

В OnBeforeDocFormSave старые (исходные) значения TV можно получить методом getTVValue (извлекает данные непосредственно из БД).

Самый корректный вариант, имхо, — это OnBeforeDocFormSave + массив data + getTVValue.
Cyrax_02
13 января 2015, 14:01
0
Пиши в modx.com
Уже в процессе:
github.com/modxcms/revolution/issues/9461
github.com/modxcms/revolution/issues/12260

Если я верно понял, в 2.3.3 должно быть исправлено…
Cyrax_02
13 января 2015, 13:17
0
Т.е. логика вызовов некорректна?
Cyrax_02
13 января 2015, 12:16
0
Наоборот. On (без Pre и без Before) — это после (в конце) выполнения события:
OnDocFormPrerender => OnDocFormRender
OnBeforeDocFormSave => OnDocFormSave
OnBeforeSnipFormSave => OnSnipFormSave
OnBeforeSnipSave => OnSnipSave
и так со всеми событиями.

Что касается событий OnDocFormPrerender и OnDocFormRender, то сначала должно генерироваться событие OnDocFormPrerender, затем OnDocFormRender. Именно так написано в справке:
Event: OnDocFormPrerender
Fires before a Resource editing form is loaded in the manager.
Event: OnDocFormRender
Fires after a Resource editing form is loaded in the manager. Useful for inserting HTML into forms.
и именно такая последовательность вызовов реализована в методах классов:
(core/model/modx/modmanagercontroller.class.php) modManagerController::render() сначала вызывает метод firePreRenderEvents(), затем firePostRenderEvents().

Там все события такие. OnSomething везде это самое начало действия Something.

Речь о render-событиях?
Поскольку последовательность вызовов, описанная в первом посте, имеет место со всеми render-процессорами, то сабжевая картина будет наблюдаться со всеми render-событиями (и с ресурсами, и со сниппетами, и с шаблонами и с TV и пр.). Другое дело — является ли эта логика вызовов корректной (запланированной) или ошибочной…
Cyrax_02
06 января 2015, 05:46
0
CustomURLs реализует вариант №3 (с заморозкой) => нельзя вручную задавать uri
AutoRedirector — вариант №2 (без заморозки), при этом обновление сайта и настроек (когда запускается стандартный генератор uri) никак не отслеживает… со всеми вытекающими…
Cyrax_02
06 января 2015, 05:04
0
Улучшенный вариант процессора:
<?php
if(!class_exists('modResourceDeleteProcessor')) {
    global $modx; include $modx->config['processors_path'].'resource/delete.class.php';
}
class sResourceDeleteProcessor extends modResourceDeleteProcessor {

    public function initialize() {
        $output = parent::initialize();        
        $this->resource->set('syncsite', $this->getProperty('syncsite', true));              // в [modResourceDeleteProcessor] кэш очищается всегда
        $this->resource->set('deleteChildren', $this->getProperty('deleteChildren', true));  // в [modResourceDeleteProcessor] удаляются всегда
        return $output;
    }
    public function deleteChildren() {
        if($this->getProperty('deleteChildren', true)) {  // в modResourceDeleteProcessor дочерние ресурсы удаляются всегда
            return parent::deleteChildren();
        } else {
	    return array();
	}
    }
    public function clearCache() {
        if($this->getProperty('syncsite', true)) {  // в modResourceDeleteProcessor кэш очищается всегда
            parent::clearCache();
        }
    }
}
return 'sResourceDeleteProcessor';

В результате в плагинах на OnDocFormDelete и OnResourceDelete можно использовать свойства «syncsite» (как в OnDocFormSave) и «deleteChildren»:
$resource->get('syncsite')
$resource->get('deleteChildren')

Свойство «syncsite» в плагинах может понадобиться, например, для очистки собственных разделов кэша, связанных с удаляемым ресурсом.
Cyrax_02
05 января 2015, 16:39
0
Зато теперь возникает проблема реализации собственного генератора URL.
Возможны 3 варианта:

1.Замена стандартного генератора uri собственным. Реализуется перегрузкой одного из методов: modx::refreshURIs() либо modResource::getAliasPath(). При каждом вызове стандартного генератора фактически будет вызываться наш собственный генератор

Плюсы:
1) Не придётся отслеживать моменты, когда и для каких ресурсов нужно выполнить перегенерацию URI — этим будет заниматься modx
2) Внутри собственного генератора URI можно легко отслеживать изменение URI и вызывать соответствующие методы Редиректора

Минусы:
1) Перегрузка классов modx или modResource реализуется не совсем чисто и не надёжно (нужно решать проблему «подсовывания» своих классов в нужных местах и в нужные моменты времени). Если для перегрузки класса modx достаточно ручной корректировки одной строки кода в 4 файлах при каждой установке и обновлении modx, то подсовывание своего класса modResource остаётся проблемой.
2) Поскольку необходимость перегенерации URI определяет modx, то при изменении тех данных, которые используются собственным генератором uri, но не используются стандартным, — при изменении этих данных собственный генератор вызываться не будет

2.Собственный генератор URI наряду со стандартным (без использования заморозки). Собственный автоматический генератор замороженные uri не трогает (так же, как и стандартный)

Плюсы:
1) Не нужно ничего перегружать
2) Сохраняется стандартная логика modx: если uri заморожен, то автоматическая генерация его затронуть не должна. Заморозка предоставляет возможность некоторым ресурсам задавать uri вручную (отлично от тех, что генерируются автоматически) и быть уверенным, что никакая «автоматка» эти uri не тронет

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

Но в автоматическом режиме задача нерешаема по следующим причинам:
а) события на генерацию URI нет
б) метод modResource::save() не генерирует никаких событий.
(Для сравнения: у элементов (плагинов, сниппетов, чанков, шаблонов, tv) при выполнении метода {ELEMENT}::save() генерируются события OnBefore{ELEMENT}Save и On{ELEMENT}Save)
в) при изменении системных настроек, настроек контекста и типов контента тоже не генерируется никаких событий

Т.е. возможно отследить только обновление сайта (событие OnSiteRefresh) и изменение/сохранение ресурса (события OnBeforeDocFormSave и OnDocFormSave)

3.Собственный генератор URI наряду со стандартным (с использованием заморозки). Собственный автоматический генератор при генерации uri их замораживает.

Плюсы:
1) Не нужно ничего перегружать
2) Нет необходимости отслеживать моменты изменения uri стандартным генератором, т.к. стандартный генератор замороженные uri не трогает

Минусы:
1) Нарушается стандартная логика modx: если uri заморожен, то собственная автоматическая генерация его затронет (например, при сохранении ресурса). Т.е. для ресурсов не будет возможности задавать uri вручную.
2) Придётся самостоятельно отслеживать изменение тех данных, которые учитываются при работе собственного генератора.
Если собственный генератор учитывает системные настройки, настройки контекстов или настройки типов контента (последнее — уж обязательно), то эта задача опять-таки в автоматическом режиме нерешаема, т.к. нет событий, наступающих при изменении этих настроек.

==========================================================================
Мой выбор — вариант №2. Сохраняющий стандартную (корректную) логику работы с замороженными url
Только как автоматически и универсально отслеживать изменение url стандартным генератором?
Cyrax_02
05 января 2015, 15:23
+1
Да, это стандартное поведение modx — обеспечение соответствия uri ресурсов псевдонимам и настройкам.

modx выполняет перегенерацию uri в 5 случаях:
1) При сохранении и копировании ресурсов (процессоры "resource/update", "resource/duplicate" и "resource/updatefromgrid")

2) Обновление сайта ("Сайт — Обновить", процессор "system/clearcache") — принудительно обновляет uri всех ресурсов. До версии modx 2.3.x перегенерацию URI при обновлении сайта не выполнял.

3) При изменении системных настроек типов контента (content type): процессоры "system/contenttype/update" и "system/contenttype/updatefromgrid"

4) При изменении системных настроек дружественных URL: процессор "system/settings/update"
5) При создании или изменении настроек дружественных URL для контекстов: процессоры "context/settings/create", "context/settings/update" и "context/settings/updatefromgrid"
Cyrax_02
04 января 2015, 15:22
0
У меня вся правая часть при отображении элемента пуста (и в Firefox, и в Chrome).

Firefox:
TypeError: b[e] is not a constructor
...,combineAndSend:function(){var a=this.callBuffer.length;if(a>0){this.doSend(a==1...ext-all.js (строка 21)

TypeError: MODx.ux is undefined
...ction() {MODx.ux.Ace.replaceComponent('modx-plugin-plugincode', 'application/x-p...index....e&id=40 (строка 41)
Chrome:
www.site.ru/manager/min/index.php?f=/assets/compon…l.plugin.js,/manager/assets/modext/sections/element/plugin/update.js Failed to load resource: the server responded with a status of 400 (Bad Request)
ext-all.js:21 Uncaught TypeError: undefined is not a function
index.php:41 Uncaught TypeError: Cannot read property 'Ace' of undefined
www.site.ru/manager/index.php?a=element/plugin/update&id=40 Failed to load resource: net::ERR_CACHE_MISS

Ну да и ладно. Хрен с ним. Главное, причина локализована.
Cyrax_02
04 января 2015, 13:57
0
— modx запускает плагин
— плагин проверяет существование нужных файлов (если их нет, выводит сообщение в логи и ничего фатального не делает)
— modx продолжает выполнение собственного кода (отображает код элемента)
Cyrax_02
04 января 2015, 12:41
0
Моё резюме по сабжу:
Риторический вопрос: позволяет ли текущая архитектура modx отобразить в админке содержимое элемента, если установлен Ace и папки assets не существует? Это я к тому, что текущее поведение modx не является единственно возможным и абсолютно верным. Технически возможна, например, более устойчивая реализация (дополнительные проверки существования файлов), когда при отсутствии папки assets modx нормально отобразит содержимое элемента при установленном Ace (или других плагинах), но без подсветки кода.

А текущее поведение modx следует принять как есть, не впадая в крайности типа "только так и должно быть" или "это фатальная проблема".
Cyrax_02
04 января 2015, 12:25
0
Речь об именах папок дополнений внутри assets?
Этот вопрос полностью решается, например, заменой всех подключаемых в html файлов вызовом специального скрипта, которому в качестве параметра передаётся обратимый хэш с ключом от имени подключаемого файла. Делать это плагином в OnWebPagePrerender или OnWebPageComplete с помощью регулярки и только для неразработчиков.

А содержимое подключаемых скриптов и стилей (в том числе в составе html) можно обфусцировать так, чтобы имена переменных, констант и css-классов там тоже были минимизированы.
Cyrax_02
04 января 2015, 08:38
0
Не зря же в настройках config.core.php предусмотрели константы
MODX_ASSETS_PATH и MODX_ASSETS_URL
Cyrax_02
04 января 2015, 08:31
-1
Так это и есть:
либо найти быстрый способ выявления причины без трассировки кода.

ядру MODX вообще не нужна эта директория для работы
Отображение правой панели (с кодом элемента/файла и пр.) — это базовый функционал modx, который не должен зависеть от дополнительно установленных компонентов (с корректным кодом) и наличия папки $modx->getOption('assets_path')
Т.е. если папка не существует, то код элемента должен нормально отображаться в правой панели, но без Ace. Мне должная логика работы видится именно такой.

Сейчас же (при установленном Ace с корректным кодом) modx'у для реализации собственного базового функционала (отображение кода элемента) требуется папка assets.
Cyrax_02
04 января 2015, 08:16
0
Поприветствуем Тайного Поклонника.

В целях какой безопасности?
Как известно, папка «assets» является одним из способов идентификации используемой CMS. А когда известна используемая CMS, ломать сайты в разы проще. Иными словами, скрывая папку assets (при соблюдении прочих «маскировочных» мер), мы существенно снижаем риск взлома сайта.
Cyrax_02
04 января 2015, 08:08
0
Ну так как раз в качестве этого «умолчательного» значения
'/assets/components/minifyx/cache/'
(и в плагине, и в настройке «minifyx_cacheFolder» при установке компонента) корректнее брать
$modx->getOption('assets_path').'components/minifyx/cache'
Cyrax_02
04 января 2015, 01:02
0
В целях безопасности. Так же, как и переименовывание папок core, manager, connectors, _build и setup.
Cyrax_02
03 января 2015, 22:02
0
В плагине MinifyX папка assets прописана железно (в 2 местах).
В остальных исходниках — всё нормально.