Валерий

Валерий

С нами с 12 октября 2015; Место в рейтинге пользователей: #633
Валерий
28 марта 2024, 22:34
0
5. Настроил компонент Login.
6. И в раздел «Редактирование данных» у уже авторизованного пользователя вывел следующий сниппет:

<?php
$modx->initialize('web');
// Проверяем, авторизован ли пользователь
if ($modx->user->isAuthenticated('web')) {
    // Получаем имя пользователя (username) из текущей сессии
    $FUusername = $modx->user->get('username');
    // ID категории, где находятся ресурсы
    $FUcategoryId = 162;
    // Получаем все ресурсы из категории с ID 162
    $resources = $modx->getCollection('modResource', array('parent' => $FUcategoryId));
    // Переменная для хранения найденного ресурса
    $foundResourceId = null;

    // Проходим по каждому ресурсу
    foreach ($resources as $resource) {
        // Получаем значение TV-поля "mentor_email" для текущего ресурса
        $mentorEmail = strtolower($resource->getTVValue('mentor_email'));

        // Сравниваем значение TV-поля "mentor_email" с именем пользователя
        if ($mentorEmail == $FUusername) {
            // Если значение TV-поля "mentor_email" совпадает с именем пользователя, сохраняем ID этого ресурса
            $foundResourceId = $resource->get('id');
            break; // Прекращаем цикл, так как уже нашли нужный ресурс
        }
    }

    // Проверяем, был ли найден ресурс с TV-полем "mentor_email" равным имени пользователя
    if ($foundResourceId) {
        $_SESSION['current_resource_id'] = $foundResourceId;
        // Если форма была отправлена
        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            // Получаем значение TV-поля "mentor_test" из отправленной формы
            $mentorTestValue = $_POST['mentor_test'] ?? '';
            $workingBusyValue = $_POST['workingBusy'] ?? '';
            $workingPersonFormatValue = $_POST['workingPersonFormat'] ?? '';

            // Получаем объект ресурса
            $resource = $modx->getObject('modResource', $foundResourceId);

            // Проверяем, был ли найден ресурс
            if ($resource) {
                // Сохраняем значение TV-поля "mentor_test"
                $resource->setTVValue('mentor_test', $mentorTestValue);
                $resource->setTVValue('workingBusy', $workingBusyValue);
                $resource->setTVValue('workingPersonFormat', $workingPersonFormatValue);
                $resource->save();
                
                // Перенаправляем пользователя на текущую страницу для предотвращения повторной отправки формы
                header('Location: ' . $_SERVER['REQUEST_URI']);
                exit();
            }
        }

        // Получаем данные ресурса
        $resource = $modx->getObject('modResource', $foundResourceId);

        // Проверяем, был ли найден ресурс
        if ($resource) {
            // Получаем значение TV-поля "mentor_test"
            $mentorTest = $resource->getTVValue('mentor_test');
            $workingBusy = $resource->getTVValue('workingBusy');
            $workingPersonFormat = $resource->getTVValue('workingPersonFormat');
            
            // Выводим значения переменных для отладки
            echo '<pre>';
            echo 'mentor_test: ' . $mentorTest . PHP_EOL;
            echo 'workingBusy: ' . $workingBusy . PHP_EOL;
            echo 'workingPersonFormat: ' . $workingPersonFormat . PHP_EOL;
            echo '</pre>';
            // Передаем данные в чанк "edit_profile_chunk" для заполнения формы
            $output = $modx->getChunk('edit_profile_chunk', array(
                'mentor_test' => $mentorTest,
                'workingBusy' => $workingBusy,
                'workingPersonFormat' => $workingPersonFormat,
                // Другие данные для заполнения формы
            ));
        } else {
            // Если ресурс не найден, выводим сообщение об ошибке
            $output = 'Ресурс не найден';
        }
    } else {
        // Если не найден ресурс с TV-полем "mentor_email" равным имени пользователя
        $output = 'Не найдено ресурсов с TV-полем ' . $FUusername .', равным имени пользователя';
    }
} else {
    // Если пользователь не авторизован, возвращаем сообщение об ошибке или что-то другое
    $output = 'Пользователь не авторизован';
}

return $output;
7. Ну и чанк, в который передаются данные и из которого формируется сама страница:

<form action="[[~[[*id]]]]" method="post" class="form-edit" id="editProfileForm">
    <div class="form-edit__input">
        <label for="mentorTest">Тестовое поле:</label>
        <span class="form-edit__note">Немного слов.</span>
        <input type="text" id="mentorTest" name="mentor_test" value="[[+mentor_test]]">
    </div>
    <div class="form-edit__select">
        <label for="workingBus">Есть свободные слоты:</label>
        <span class="form-edit__note">Поставить значение «нет» в том случае, когда у вас нет свободных мест для работы с студентами.</span>
        <select id="workingBusy" name="workingBusy">
            <option value="0" [[!If? &subject=`[[+workingBusy]]` &operator=`=` &operand=`0` &then=`selected`]]>Да</option>
            <option value="1" [[!If? &subject=`[[+workingBusy]]` &operator=`=` &operand=`1` &then=`selected`]]>Нет</option>
        </select>
    </div>
    <div class="form-edit__select">
        <label for="workingBus">Доступный формат приема:</label>
        <span class="form-edit__note">Внимание! Указывать формат, который вам разрешен для проведения сертификационных сессий.</span>
        <select id="workingPersonFormat" name="workingPersonFormat">
            <option value="0" [[!If? &subject=`[[+workingPersonFormat]]` &operator=`=` &operand=`0` &then=`selected`]]>Очно</option>
            <option value="1" [[!If? &subject=`[[+workingPersonFormat]]` &operator=`=` &operand=`1` &then=`selected`]]>Онлайн</option>
            <option value="2" [[!If? &subject=`[[+workingPersonFormat]]` &operator=`=` &operand=`2` &then=`selected`]]>Оба варианта</option>
        </select>
    </div>
    <!-- Другие поля для редактирования -->
    
    <!-- Кнопка для отправки формы -->
    <button type="submit" class="btn btn_green btn_forSave">Сохранить</button>
</form>
<script>
    // JavaScript для предотвращения множественных отправок формы
    document.getElementById('editProfileForm').addEventListener('submit', function(event) {
        // Проверяем, была ли форма отправлена ранее
        if (this.getAttribute('data-submitted') === 'true') {
            // Если форма уже была отправлена, предотвращаем повторную отправку
            event.preventDefault();
            return;
        }

        // Отмечаем форму как отправленную
        this.setAttribute('data-submitted', 'true');

        // Отключаем кнопку "Сохранить"
        document.getElementById('saveButton').disabled = true;

        // Отправляем форму асинхронным запросом
        var formData = new FormData(this);
        var xhr = new XMLHttpRequest();
        xhr.open('POST', this.action);
        xhr.onload = function() {
            if (xhr.status === 200) {
                // Если запрос выполнен успешно, перезагружаем страницу
                location.reload();
            } else {
                // Если произошла ошибка, разрешаем повторную отправку формы
                document.getElementById('editProfileForm').removeAttribute('data-submitted');
                document.getElementById('saveButton').disabled = false;
            }
        };
        xhr.send(formData);
    });
</script>
Собственно все. Подозреваю, что с выводом TV полей уже для редактирования можно было бы как-то лучше разобраться, но пока такой формат работает и нагрузки лишней нет. Есть проблемы с мультиполями, с ними еще работаю.
Валерий
28 марта 2024, 22:31
0
В итоге сделал, все работает корректно. Но пошел по пути написания сниппета и небольшого «одноразового» сниппета для регистрации пользователей. Оставлю тут, может кому пригодится.
Конечно, код далек от идеального, я так и не добрался до php в чистом виде, только наверстываю. Может кто-то укажет на явные косяки и чрезмерность (стартовый каркас писал с помощью ChatGPT, потом уже все в рабочий вид превращал).

1. Вначале отсортировал в JSON файл всех сотрудников, у которых есть почты (было решено опираться на соответствие почты в карточках и у пользователя).
2. Вывел JSON с параметрами email и name (на самом деле больше параметров, но нужны для конкретной цели только эти два).
3. Создал группу для пользователей с нужными мне настройками доступа (работа ВНЕ админки).
4. Написал сниппет:
<?php
$usersJsonPath = 'https://migip-reg.ru/tehnicheskie-stranicy/fullstuff-list.json'; // Укажите путь к вашему JSON файлу

// Функция для создания случайного пароля
function generateRandomPassword($length = 8) {
    $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    $password = '';
    for ($i = 0; $i < $length; $i++) {
        $password .= $characters[rand(0, strlen($characters) - 1)];
    }
    return $password;
}

// Получение данных из JSON файла
$jsonData = file_get_contents($usersJsonPath);
if ($jsonData === false) {
    // Выводим сообщение об ошибке, если не удалось получить данные из JSON
    echo 'Не удалось получить данные из JSON файла';
} else {
    // Данные из JSON получены успешно, декодируем их
    $usersData = json_decode($jsonData, true);
    
    // Проверяем, произошла ли ошибка при декодировании JSON
    if (json_last_error() !== JSON_ERROR_NONE) {
        echo 'Ошибка при декодировании JSON: ' . json_last_error_msg();
    } else {
        // Данные из JSON успешно декодированы, выводим их для отладки
        echo '<pre>';
        print_r($usersData);
        echo '</pre>';
        
        // Проходим по каждому пользователю и создаем его в MODX
        foreach ($usersData as $userData) {
            $email = strtolower($userData['email']);
            $fullName = $userData['name'];

            // Проверка на существование пользователя с таким email
            if (!$modx->getObject('modUser', array('email' => $email))) {
                // Пользователя с таким email не существует, создаем нового
                $user = $modx->newObject('modUser');
                $user->set('username', $email); // Используем email в качестве имени пользователя
                $user->set('email', $email);
                $user->set('password', generateRandomPassword()); // Генерируем случайный пароль
                $user->set('active', 1); // Устанавливаем пользователя активным
                
                // Создаем профиль пользователя
                $profile = $modx->newObject('modUserProfile');
                $profile->set('internalKey', $user->get('id')); // Устанавливаем внутренний ключ профиля равным ID пользователя
                $profile->set('fullname', $fullName); // Устанавливаем полное имя
                $profile->set('email', $email); // Устанавливаем адрес электронной почты

                // Присоединяем профиль к пользователю
                $user->addOne($profile);

                // Сохраняем пользователя
                $user->save();

                // Добавляем пользователя в группу "Stuff"
                $user->joinGroup('Stuff');
                $user->save();
            }
        }
    }
}
Таким образом были созданы все пользователи с именем пользователя и почтой = почты в карточках специалистов, и полным именем из карточек специалистов.
Валерий
21 марта 2024, 21:18
0
В целом да, план примерно такой, когда какой-то элемент у созданного пользователя, будет соотноситься с имеющимся ресурсом (просто сначала сделали ресурсы, а потом спустя пару лет решили делать кабинеты). Спасибо за наводку на компонент, изучу.
Валерий
19 ноября 2023, 12:32
0
Добрый день! Спасибо за сборку, некоторым клиентам помогает. Но столкнулся с проблемой вставки Iframe с Youtube. При первом сохранении все хорошо, но после переключения в визуальный режим редактора к iframe добавляется sandbox="" и видео с фронта пропадает. Причем иногда просто черный экран, а иногда говорит про JS, который надо включить )).
Я так понял, это встроенная функция редактора, и вроде как должна помочь запись в файле конфигурации
config.iframe_attributes = {
    sandbox: 'allow-scripts allow-same-origin',
    allow: 'autoplay'
}
Вот только у меня не помогает. Может файл конфигурации где-то в другом месте находится? Я правил вот тут: manager/assets/components/ckeditor/ckeditor

Кто как решал эту проблему?
Валерий
13 октября 2023, 12:52
+1
Нашел-таки в документации параметр:
&useWeblinkUrl=`0`
Поставил его в 0 и все заработало. Не супер-очевидно по описанию в документации было. Ну да ладно, работает теперь.
Валерий
13 октября 2023, 12:22
+1
В любом случае спасибо за участие. Если до конца дня найду выход, напишу сюда, чтобы осталось на будущее.
Валерий
13 октября 2023, 12:22
0
Неа, не хочет pdoMenu видеть в «Публикациях» родителя :)
Странное поведение. Нашел в в старых своих заметках от 2016 года аж такой же вопрос, тогда мне никто так и не ответил. Похоже, не лечится, придется редиректить, плохо, что на Таймвеб этот редирект не совсем корректно отрабатывает из-за специфики url'а
Валерий
13 октября 2023, 12:12
0
Вы просто добавили видимость блоку :) Конечно, оно на место встанет, CSS-то насторено.
Суть в том, что пункт «Публикации» должен иметь класс «top-level__item_current», который ему присваивается, если pdoMenu корректно отлеживает родителя.

В общем, дело не в CSS, а чисто в выводе на уровне php.
Валерий
13 октября 2023, 11:11
0
Только что перепроверил когда и как выдаются параметры оформления. Там реально получается, что «Публикации» не считаются родителем «Видео, интервью..» (хотя это не так), если «Публикации» являются ссылкой на «Статьи».
Либо pdoMenu такое не умеет отслеживать, либо есть какой-то недокументированный параметр с оформлением подобных пунктов :(
Валерий
13 октября 2023, 11:07
0
Вы не туда зашли. Я вас запутал, признаю. В примере использовал раздел «Обо мне», но когда давал ссылку, там написал, что нужно смотреть в «Публикации». Попробуйте там перейти на любую подкатегорию, например «Видео, интервью...»
Валерий
13 октября 2023, 10:53
0
Не, к сожалению, не так просто с этим. Сам wrapper ведь не влияет на присвоение классов. А там именно класс активности не присваивается родительскому пункту, если переходить по подкатегориям.

Такое ощущение, что я какой-то из чанков не указал вовсе. Или не добавил в него класс активности.
Валерий
13 октября 2023, 10:34
0
Ну и если здесь можно временно разместить ссылку, то вот так это на сайте — mariadolgopolova.ru/publikatsii/stati/

Если просто «Публикации», то переход на «Статьи» нормальный, а вот если перейти на «Видео, интервью и т.д», то меню пропадает. Точнее, категория «Публикации» перестает считаться активной.
Валерий
13 октября 2023, 10:32
0
Сейчас попробую.
Вызов меню. У меня оформление меню вставляется через чанки, но сюда для упрощения (надеюсь) добавил само содержимое чанков. По этому так оформлено, на сайте все корректно поставлено:
<nav class="menu">
    <a class="icon-home" title="Вернуться на главную" aria-label="Вернуться на главную" href="/"><svg viewBox="-4.5 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M19.469 12.594l3.625 3.313c0.438 0.406 0.313 0.719-0.281 0.719h-2.719v8.656c0 0.594-0.5 1.125-1.094 1.125h-4.719v-6.063c0-0.594-0.531-1.125-1.125-1.125h-2.969c-0.594 0-1.125 0.531-1.125 1.125v6.063h-4.719c-0.594 0-1.125-0.531-1.125-1.125v-8.656h-2.688c-0.594 0-0.719-0.313-0.281-0.719l10.594-9.625c0.438-0.406 1.188-0.406 1.656 0l2.406 2.156v-1.719c0-0.594 0.531-1.125 1.125-1.125h2.344c0.594 0 1.094 0.531 1.094 1.125v5.875z"></path></svg></a>
    [[!pdoMenu?
        &parents=`-1,-29,-44,-168,-775`
        &level=`2`
        &includeTVs=`icon_prev,class_item`
        &tplOuter=`<ul class="menu__top-level top-level">[[+wrapper]]</ul>`
        &tpl=`<li class="top-level__item"><a class="top-level__link" href="[[+link]]" [[+attributes]]>[[+pagetitle]]</a>[[+wrapper]]</li>`
        &tplHere=`<li class="top-level__item top-level__item_current active"><a class="top-level__link" href="[[+link]]" [[+attributes]]>[[+pagetitle]]</a>[[+wrapper]]</li>`
        &tplParentRow=`<li class="top-level__item"><a href="[[+link]]" class="top-level__link" [[+attributes]]>[[+pagetitle]]</a></li>[[+wrapper]]`
        &tplParentRowHere=`<li class="top-level__item active top-level__[[+classnames]] "><a href="[[+link]]" class="top-level__link" [[+attributes]]>[[+pagetitle]]</a></li>[[+wrapper]]`
        &tplParentRowActive=`<li class="top-level__item active top-level__[[+classnames]]"><a href="[[+link]]" class="top-level__link" [[+attributes]]>[[+pagetitle]]</a></li>[[+wrapper]]`
        &tplInner=`<ul class="menu__second-level [[+classnames]]">[[+wrapper]]</ul>`
        &tplInnerRow=`<li class="second-level__item second-level__[[+classnames]] second-level__item_[[+icon_prev]]"><a href="[[+link]]" class="second-level__link" [[+attributes]]><span class="second-level__icon">[[+class_item]]</span>
        <span class="second-level__title">[[+menutitle]]</span></a></li>[[+wrapper]]`
        &tplInnerHere=`<li class="second-level__item second-level__[[+classnames]] second-level__item_[[+icon_prev]]"><a href="[[+link]]" class="second-level__link" [[+attributes]]><span class="second-level__icon">[[+class_item]]</span><span class="second-level__title">[[+menutitle]]</span></a>[[+wrapper]]</li>`
        &hereClass=`item_current`
        &firstClass=``
        &lastClass=``
    ]]
</nav>
Валерий
24 июня 2023, 16:04
0
Благодарю. Посижу с этим обязательно.
Пока как раз на яндекс.почту перешел (на SMTP через них), у нас платный аккаунт, так что пока в деле.
Валерий
24 июня 2023, 09:22
0
Тогда будет задержка в несколько секунд, во время отправки. Иногда до 5 секунд доходит.
Было интересно, возможно ли в FormIt такое привязать. Странно, что это не реализовано.
Валерий
14 июня 2023, 16:12
0
А вот у меня не сработала альтернативная проверка.
Единственное, у моей формы работает валидация на большинстве устройств, а вот у одного сотрудника на Safari 14 проверка не осуществляется и форма переходит на страницу «Спасибо». Сама форма, само собой, не отправляется.

Как думаете, что еще можно сделать? Кроме насильного обновления браузера…

[[!AjaxForm?
    &snippet=`FormIt`
    &preHooks=`Formit2AjaxUpload`
    &hooks=`AjaxUpload2Formit,AjaxUploadAttachments,pdf,email,FormItAutoResponder`
    &ajaxuploadFieldname=`image`
    &ajaxuploadTarget=`images/user/`
    &ajaxuploadUid=`image`
    &form=`tpl_form_ind_member`
    &emailTpl=`tpl_email`
    &pdfTpl=`tpl_PDF_ind_member`
    &cssTpl=`tpl_css_user`
    &author=`orgi_ru`
    &title=`Заявка: Гештальт-терапевт, действительный член`
    &emailSubject=`Заявка: Гештальт-терапевт, действительный член`
    &emailTo=`ysilence@yandex.ru,argigt@mail.ru`
    &emailFrom=`info@argigt.ru`
    &fiarReplyTo=`argigt@mail.ru`
    &fiarFrom=`info@argigt.ru`
    &fiarSender=`info@argigt.ru`
    &fiarFromName=`АРГИГТ`
    &fiarTpl=`tpl_email`
    &fiarToField=`email_sender`
    &fiarSubject=`Анкета на вступление в ассоциацию`
    &validate=`email_sender:email:required, fio_sender:required, phone_sender:required, passportNumber_sender:required, passportMVD_sender:required, passportDate_sender:required, adress_sender:required, born_sender:required, workPlace_sender:required, workPost_sender:required, instName_sender:required, instArgigt1_sender:required, instArgigt2_sender:required, instArgigt3_sender:required`
    &validationErrorMessage=`Ошибка в форме`
    &successMessage=`Сообщение отправлено`
    &submitVar=`fizassociate`
]]
И скрипт:

$(function(){
    $(document).on('af_complete', function(event, response) {
        var form = response.form;
        if (form.attr('id') == 'form-anketa' && response.success) {
    	   window.location.href = "https://argigt.ru/vasha-zayavka-otpravlena.html"
        }
    });
});
Валерий
04 июня 2023, 11:36
0
Понял. Тогда придется переносит все на Modx2. Благо, все еще не сложно это сделать.
Спасибо.
Валерий
04 июня 2023, 11:09
0
В магазине появилась бета, 1.14.12, она продается и устанавливается на Modx3 с 25 мая.
И даже в описании уже написано: «Внимание, этот компонент требует версию MODX не ниже 3.0 !»

Я осознаю, что бета, это предварительная версия и могут быть ошибки в работе. Я даже не с претензией писал, а просто как пользователь, столкнувшийся с проблемой в продукте.
Валерий
04 июня 2023, 06:58
0
Вот ошибка, которая появляется, при выбранной версии php 7.4
argigt.ru [Sun Jun 04 06:37:16 2023] [error] [pid 79483] sapi_apache2.c(349): [client 171.6.244.230:46064] PHP Fatal error:  Uncaught Error: Cannot access protected property ModxPro\\PdoTools\\Fetch::$timings in /home/c/-------/public_html/core/cache/includes/elements/modx/revolution/modsnippet/35.include.cache.php:319
\nStack trace:
\n#0 /home/c/-------/public_html/core/src/Revolution/modScript.php(88): include()
\n#1 /home/c/-------/public_html/core/src/Revolution/modParser.php(505): MODX\\Revolution\\modScript->process(NULL)
\n#2 /home/c/-------/public_html/core/components/pdotools/src/Parsing/Parser.php(276): MODX\\Revolution\\modParser->processTag(Array, true)
\n#3 /home/c/-------/public_html/core/src/Revolution/modParser.php(218): ModxPro\\PdoTools\\Parsing\\Parser->processTag(Array, true)
\n#4 /home/c/-------/public_html/core/components/pdotools/src/Parsing/Parser.php(73): MODX\\Revolution\\modParser->processElementTags('', '<!DOCTYPE html>...', true, false, '[[', ']]', Array, 9)
\n#5 /home/c/-------/public_html/core/src/Revolution/modResource.php(521): ModxPro\\PdoTools\\Parsing\\Parser->processElementTags('', '<!DOCTYPE html>...', true, false, '[[',  in /home/c/-------/public_html/core/cache/includes/elements/modx/revolution/modsnippet/35.include.cache.php on line 319