Всего 123 795 комментариев

Сергей С
05 ноября 2024, 10:23
0
Нужно стандартный чанк изменить или предварительно копию сделать, И на строке 155 изменить стиль window.clusters = geoObjects.search(«geometry.type == 'Point'»).clusterize({ preset: 'islands#blackClusterIcons'});
Александр
04 ноября 2024, 11:44
0
А для чего удалили ссылку на $customer в методе getCustomerId? Теперь в событие msOnBeforeGetOrderCustomer передается всегда null и после события тоже всегда null и осталась бесполезная проверка, которая всегда выполняется, при этом на $customer в событии msOnBeforeGetOrderCustomer никак не повлиять, об этом даже pull request есть. Верните, пожалуйста, ссылку обратно)
Александр Туниеков
04 ноября 2024, 04:49
+1
Еще сейчас заметил у Артура редактируется выбранная группа пользователей. Чтоб редактировать группу 2 в gettables надо добавить в секцию pdoTools where:
'where'=>[
    'modUser.primary_group' => 2,
    'modUser.active' => 1,
]
Александр Туниеков
04 ноября 2024, 04:36
0
Забыл. getTables работает в MODX2. В MODX3 тоже вроде пока работает, но там не гарантируется и приспосабливать getTables для MODX3 не планируется. Работу с произвольной таблицей в MODX3 вроде сильно усложнили и не понятно как сделать правильно.
Александр Туниеков
04 ноября 2024, 03:47
+1
Кстати GRUD в getTables реализован и можно его использовать для подобной задачи :-). У пользователей MODX 2 таблицы и не так просто. Но можно попробовать.

На странице на которую ограничен доступ пишем сниппет:
{'!getTable' | snippet : [
    'table'=>[
        'event'=>1,
        'class'=>'modUser',
        'actions'=>[
            'create'=>[],
            'update'=>[],
            'remove'=>[],
            'export_excel'=>[],
        ],
        'pdoTools'=>[
            'class'=>'modUser',
            'leftJoin'=>[
                'modUserProfile'=>[
                    'class'=>'modUserProfile',
                    'on'=>'modUserProfile.internalKey = modUser.id'
                ]
            ],
            'select'=>[
                'modUser'=>'modUser.id',
                'modUserProfile'=>'modUserProfile.fullname,modUserProfile.email,modUserProfile.phone',
            ],
            'sortby'=>[
                'modUser.id'=>'DESC'
            ]
        ],
        'row'=>[
            'id'=>['filter'=>1],
            'password'=>[
                'edit'=>['type'=>'hidden'],
                'default'=>'Не секретный пароль'
            ],
            'fullname'=>[
                'class'=>'modUserProfile',
                'label'=>'ФИО',
                'edit'=>['type'=>'text','search_fields'=>['internalKey'=>'id'],],
                'filter'=>1,
            ],
            'email'=>[
                'class'=>'modUserProfile',
                'label'=>'email',
                'edit'=>['type'=>'text','search_fields'=>['internalKey'=>'id'],],
                'filter'=>1,
            ],
            'phone'=>[
                'class'=>'modUserProfile',
                'label'=>'Телефон',
                'edit'=>['type'=>'text','search_fields'=>['internalKey'=>'id'],],
                'filter'=>1,
            ],
        ]
    ]
]}
Пишем плагин на событие getTablesAfterUpdateCreate. Для работы плагина в сниппете должно быть указано 'event'=>1, как выше.
<?php
switch ($modx->event->name) {
    case 'getTablesAfterUpdateCreate':
        // $modx->log(1,'getTablesAfterUpdateCreate '.print_r($data,1));
        if($data['table_name'] == 'modUser' and $data['gts_action'] == 'getTable/create'){
            if($modUser = $modx->getObject('modUser',(int)$data['id'])){
                $modUser->set('username',$data['email']);
                $modUser->set('password',md5(date('d.m.Y H:i:s')));
                $modUser->joinGroup(2);
                $modUser->save();
            }
        }
    break;
}
И все работает :-).


Так же можно это же сделать с PVTables, но этот компонент я еще не добрался опубликовать :-(. И писать в 2 таблицы сразу там не сделанно. И события не все прописал :-(.

Безопасность обеспечивается хеш-кодом. Страница на которой опубликован сниппет должна быть доступна только нужным пользователям. Использовать getTables, для подобных задач, думаю, проше и быстрее чем писать контроллеры для sendIt.
Александр Туниеков
04 ноября 2024, 02:38
0
Какая версия MySQL? На MySQL 8 возникала проблема. Он почему-то не воспринимает двойную сортировку.
sort by pagetitle ASC, createon DESC
И MySQL 8 возвращает ошибку. В коде от Ильи двойная сортировка используется и нужна. Когда с этой ошибкой столкнулся не было времени ее решать, но на всякий случай сейчас MySQL 8 не ставлю.
Александр Туниеков
04 ноября 2024, 02:25
0
Тоже интересно что с безопасностью. В коде на гитхабе никаких проверок на доступ. Возможно безопасность обеспечивает SendIt, но автор вообще не указал как SendIt подключается и используется. Наверно в SendIt подключаются прессеты??? В общем, для человека не знакомого с SendIt, как мне, статья вообще не понятная.

Безопасность может быть реализованна таким образом. Сниппет, типа AjaxForm, при обработки страницы, записывает в сессию хеш-код. js в браузере отправляет с формой этот хеш-код. Обработчик ajax запросов на сервере смотрит есть ли в сесии этот хеш-код и если его нет, то возращяет ошибку.
Таким образом, если сниппет не был вызван при обработке страницы, то все ajax запросы завершаться ошибкой. Будут приняты только те запросы с правильным хеш-кодом.
А на ресурс MODX можно поставить ограничения и показывать его только разрешенным пользователям. Соответственно на странице на запрещенном ресурсе сниппет не отработал, хеш-код в сессию не записался и ajax запросы не срабатывают.

В общем не знаю, как безопасность реализованна в SendIt, но наверно что-то подобное. Надеюсь @Артур Шевченко просветит нас :-)
Ivan K.
02 ноября 2024, 22:21
0
Сегодня столкнулся с подобной проблемой.
MODX3 + php8.1

Выяснил, что причина в слеше в начале твшки с картинкой.
Решил топорным методом.
[[pthumb? &input=`[[+tv.foto:replace=`/assets/files/==assets/files/`]]` &options=`w=250&h=180&zc=1`]]
Вдруг кому пригодится.
Pavel
02 ноября 2024, 18:09
0
вопрос с текстом был решен в «Управление словарями», а вот со скриптами прищлось редактировать php файл сниппета и комментировать некоторые js и css файлы
Pavel
02 ноября 2024, 16:42
0
Спасибо большое за решение, я думаю попробовать его для аренды техники — тоже посуточно.
Правда появились вопросы — везде теперь написано «аренда номера» и надо это как-то мне выпиливать.
И второе — подключается bootstrap и jq которые у меня уже подключены и хотелось бы иметь возможность их отключить ((
Благодарю
newbmod
02 ноября 2024, 12:47
0
Здравствуйте!
Работает только с единичными адресами? Маски, подсети?
Денис Усманов
02 ноября 2024, 10:59
0
Артур, молодец! Очень нужное решение, я долго «выкладывал» свой код по такому же кейсу) Ты оказался быстрее, так держать!
Ivan K.
01 ноября 2024, 12:53
0
Здравствуйте.
Отличное и нужное решение. Обязательно воспользуюсь.
Но хотел уточнить не возникнет ли проблем при использовании MODX3 + php8.1?
И в плане безопасности можно ли использовать в «личном кабинете пользователя» (простые юзеры, которые залогинены в контексте web) данное решение? хотел кастомную таблицу подключить, чтобы юзеры меняли в ней данные.
Евгений
01 ноября 2024, 12:00
0
благодарю, то что нужно!!! сейчас проверим как работает
по идее если там у плагина пакета оставить только на дубликейте событие то он будет урл делать при дубле же? )
Андрей Шевяков
01 ноября 2024, 09:57
+1
Добрый день!
Можно использовать дополнение CustomUrls
Пример как с ним работать тут Ссылка
Сергей
31 октября 2024, 08:24
0
Володя, подскажи пожалуйста на какое событие нужно создать скрипт, что бы при фильтрации через msearch2 выбиралась нужная опция. Сейчас работает только при повторном обновлении страницы в дефолтным классом. И почему у кастомного msopfilters.class.php нет выбора нужной опции при фильтрации. И почему то при добавлении зависимостей, очень медленно работает. Речь о фильтрации и выводе в каталоге.
Дмитрий
30 октября 2024, 13:44
+1
Спасибо! Очень информативно
Сергей Шлоков
30 октября 2024, 11:46
+3
Как по мне, чересчур громоздко. Логика с date и start/end не очевидна. Да и в коде слишком много лишней логики. Я бы предложил вариант с датой и длительностью (просто в целях разминки полушарий)
$date = $modx->getOption('date', $scriptProperties, '');
$duration = $modx->getOption('duration', $scriptProperties, '1');
$chunk = $modx->getOption('tpl', $scriptProperties, '');

if (empty($date) || empty($chunk)) {
  return '';
}

[$day, $month, $year] = sscanf($date, "%d.%d.%d");
$year ??= date('Y');
$date = "$day.$month.$year";

$currentTimestamp = time();
$startTimestamp = strtotime($date);
$endTimestamp = strtotime($date . " + $duration days");

if ($currentTimestamp >= $startTimestamp && $currentTimestamp < $endTimestamp) {
  $pdoTools = $modx->getService('pdoTools');
  return $pdoTools->getChunk($chunk);
}
Указал год — сработает только для него. Не указал, ежегодно. Если длительность не указана, то она равна 1 дню.
Артур Шевченко
28 октября 2024, 19:51
+1
Немного сократил и добавил поддержку файловых чанков.
<?php
$start = $modx->getOption('start', $scriptProperties, '');
$end = $modx->getOption('end', $scriptProperties, '');
$chunk = $modx->getOption('tpl', $scriptProperties, '');

// определяем в каких случаях мы ничего не будем делать, нам важно не перетрудиться.
if((!$start && !$end) || !$chunk){
    return '';
}
// завозим поддержку файловых чанков
if(!$parser = $modx->getService('pdoTools')){
    $parser = $modx;
}

$now = strtotime('d.m.Y');
$currentYear = date('Y');
// предполагается что дада передаётся строкой вида "d.m"
$startTime = strtotime($start . '.' . $currentYear);

// если задана только дата начала, считае, что оформление будет активно только в эту дату
if(!$end){
    if($now === $startTime){
        return $parser->getChunk($chunk);
    }
}

$startParts = explode('.', $start);
$endParts = explode('.', $end);

// проверяем больше месяц даты начала месяца даты окончания
if((int)$startParts[1] > (int)$endParts[1]){
    $endTime = strtotime($end . '.' . ($currentYear + 1));
}else{
    $endTime = strtotime($end . '.' . $currentYear);
}

if ($now < $startTime || $now > $endTime) {
   return '';
}
return $parser->getChunk($chunk);