Top.Mail.Ru

Хуки FormIt. Пишем хук для авторизации пользователя на Frontend

В данном руководстве я покажу, как можно при помощи хуков FormIt реализовать более сложную логику формы, обрабатываемой при помощи сниппета FormIt, чем просто стандартная отправка email. Конкретно в данном примере разберем, как можно сделать форму авторизации, построенную на FormIt и AjaxForm.

}

Автор материала

. Веб-разработчик, создатель проекта Лектория, эксперт MODX Revolution, директор веб-студии OpenColour. Youtube-канал OpenModx.

7 минут на прочтение
Теги по теме:

Для чего все это нужно и почему не компонент Login?

Не знаю, почему, но за всю свою многолетнюю практику работы с MODX Revolution, я использовал компонент Login только один раз. Отличие Login от FormIt состоит в том, что Login решает ряд задач, посвященных конкретно авторизации/регистрации и редактированию профиля пользователя на Frontend, а FormIt — это более универсальный компонент, с помощью которого можно построить практически любую логику обработки формы, но придется немного покодить. Если перед вами не стоит задача построить сайт с регистрацией и авторизацией на Frontend за час, то я бы предпочел исползовать FormIt, написав для него несколько хуков, вместо того, чтобы разбираться в Login и кастомизировать его формы, доступные по-умолчанию.

Я буду использовать ниже синтаксис Fenom вместо стандартного синтаксиса MODX.

В предыдущей статье я разбирал принцип работы FormIt. При работе с FormIt в чистом виде необходимо в самой форме добавлять дополнительные плейсхолдеры для вывода значений ошибок, значений полей и так далее. Для того, чтобы упростить себе жизнь, можно использовать данный компонент в связке с AjaxForm, что позволит сделать формы асинхронными и избавит вас от необходимости вставлять упомянутые выше плейсхолдеры.

Создаем html-код формы авторизации

На данном шаге нам необходимо создать болванку (html-код) нашей формы, которую мы в дальнейшем будем наполнять логикой.

Возьмем для примера такой код (взят из вполне конкретного проекта):

<form>
    <ul class="field_list">
        <li class="field_item">
            <dl class="form_cell form_cell_v1_mod">
                <dt class="form_cell_title form_v1_mod hline_hide_mod">
                    <label for="signin_email2">Email</label>
                </dt>
                <dd class="form_field_wrap form_v1_mod hline_hide_mod">
                    <input class="form_field v2_mod default_mod" type="text" id="signin_email2" placeholder="Email*" name="username"/>
                    <span class="form_field_error" data-error-for="username"></span>
                </dd>
            </dl>
        </li>
        <li class="field_item">
            <dl class="form_cell form_cell_v1_mod">
                <dt class="form_cell_title form_v1_mod hline_hide_mod">
                    <label for="signin_password2">Пароль</label>
                </dt>
                <dd class="form_field_wrap form_v1_mod hline_hide_mod">
                    <input class="form_field v2_mod default_mod" type="password" id="signin_password2" placeholder="Пароль*" name="password"/>
                    <span class="form_field_error" data-error-for="password"></span>
                </dd>
            </dl>
            <span class="btn_field">Показать</span>
        </li>
    </ul>
    <div class="form_btn_w offset_mod">
        <button type="submit" name="sendSignin" value="1" class="btn_form">ВОЙТИ</button>
    </div>
</form>

Создаем чанк с именем b.signinForm и помещаем в него код формы в том виде, в котором он показан выше. Далее мы будем вызывать данный чанк в параметрах сниппета AjaxForm.

Делаем вызов сниппета AjaxForm в связке с FormIt

Для того, чтобы наша форма хотя бы просто отобразилась на странице, необходимо в том месте, где она должна размещаться, поставить вызов сниппета AjaxForm.

{$_modx->runSnippet('!AjaxForm', [
    'form' => 'b.signinForm',
    'hooks' => 'ЗДЕСЬ МЫ УКАЖЕМ ИМЯ НАШЕГО ХУКА',
    'validate' => 'username:required,password:required',
    'validationErrorMessage' => 'Во время авторизации возникли ошибки',
    'successMessage' => 'Авторизация успешно завершена',
    'submitVar' => 'sendSignin',
])}

Не важно, запускаете вы сниппет AjaxForm или FormIt, его необходимо вызывать без кэширования (с восклицательным знаком спереди), так как при любой загрузке страницы нам нужен свежий вызов, а не "слепок" из кэша.

Валидация полей

FormIt имеет встроенный механизм валидации полей. Правила валидации мы можем задать в параметре validate. Прежде, чем будет запущен какой-либо хук из параметра hooks, все поля будут прогнаны через указанные правила валидации. В нашем случае, это простое правило required, которое проверит, есть ли хотя бы один символ во введенных полях. Если поля успешно прошли валидацию, будет запущен первый хук из цепочки хуков, указанных в параметре hooks через запятую. В нашем случае мы создадим один хук под названием loginHook.

Что такое хук?

Для простоты понимания, хук — это сниппет, который запускается изнутри механизмов FormIt. Данный сниппет создается точно так же, как и все остальные сниппеты, а на входе такой сниппет принимает параметр $hook.

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

Более подробно об этом написано здесь.

Но! И это еще не все! Вы можете проводить валидацию полей внутри хуков, что бывает также удобно.

Наполняем наш хук кодом

Сперва добавьте в параметр hooks в вызове сниппета AjaxForm или FormIt значение loginHook:

...
'hooks' => 'loginHook',
...

После чего необходимо создать сниппет loginHook, код которого нас сейчас будет интересовать больше всего.

<?php
/**
 * Авторизация пользователя в текущем контексте
 *
 * @var modX $modx
 * @var fiHooks $hook
 */

//Формируем набор свойств, который мы передадим 
//в процессор авторизации, который есть в modx по-умолчанию
$properties = array(
    'login_context' => $modx->context->key,
    'add_contexts' => '',
    //Для обращения к полям, введенным в форме, 
    //используется метод $hook->getValue('имя поля')
    'username' => $hook->getValue('username'),
    'password' => $hook->getValue('password'),
    'returnUrl' => '',
    'rememberme' => true,
);

// Запуск процессора авторизации
/** @var modProcessorResponse $response */
$response = $modx->runProcessor(
    'user/login',
    $properties,
    [
        //Путь к папке процессора
        'processors_path' => MODX_CORE_PATH.'model/modx/processors/security/',
    ]
);

// Проверка результата на ошибки. Возвращение ошибок в форму, если нужно
/** @var modProcessorResponseError[] $errors */
if($errors = $response->getFieldErrors()) {
    foreach ($errors as $error) {
        //Таким образом мы можем добавить ошибку к определенному полю
        $hook->addError($error->getField(), $error->getMessage());
    }

    //Если хук возвращает false, выполнение
    //последующих хуков останавливается
    return false;
}

//Получить объект текущего авторизовавшегося пользователя можно так:
$user = $modx->getAuthenticatedUser($modx->context->key);

//Здесь можно выполнить дополнительную логику после 
//авторизации ползователя (инициализацию каких-либо полей и прочие операции)

//Хук должен вернуть true, тогда будут выполнены 
//все остальные операции и будет считаться, что он завершился успешно
return true;

В данном примере авторизация пользователя осуществляется через встроенный в modx процессор login. Если ваша логика авторизации отличается от встроенной логики авторизации modx, вы можете создать собственный процессор, наследующий класс процессора login, или написать код авторизации непосредственно в хуке.

Таким образом, вызов AjaxForm ниже в связке с хуом loginHook и формой b.signinForm позволит вам реализовать форму авторизации пользователя на сайте:

{$_modx->runSnippet('!AjaxForm', [
    'form' => 'b.signinForm',
    'hooks' => 'loginHook',
    'validate' => 'username:required,password:required',
    'validationErrorMessage' => 'Во время авторизации возникли ошибки',
    'successMessage' => 'Авторизация успешно завершена',
    'submitVar' => 'sendSignin',
])}

MODX FormIt. Создание форм с произвольной логикой

Как быстро понять суть работы FormIt и использовать данный компонент для обработки любых форм.

Читать

Начальный курс по теме

Артем Зернов
Комментарии
  1. Сергей Шумков 07 марта 2023, 13:33 # 0

    Спасибо за интересную статью Но почему то не работает?? использовал стандартный вывод [[!AjaxForm? &form=signinForm &hooks=loginHook &validate=username:required,password:required &validationErrorMessage=В форме содержатся ошибки! &successMessage=Вход успешно выполнен! &submitVar=sendSignin ]]

    1. Артем 07 марта 2023, 13:38 # 0

      А что-нибудь в консоли браузера есть? Запрос на сервер улетает?

      Если улетает, тогда нужно посмотреть, проходят ли валидацию все поля. Если не проходят, то нужно искать проблему в валидации.

      Если проходят, то нужно посмотреть, запускается ли сниппет loginHook. Если не запускается, то нужно проверить, нет ли опечаток в названии сниппета и выяснить, почему он не запускается.

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

    2. Сергей Шумков 07 марта 2023, 13:45 # 0

      при отправки выдает сообщение: Форма успешно отправлена, хотя должно быть Авторизация успешно завершена. Как можно проверить валидацию, и запуск хука loginHook? уже 2 час ковыряюсь проверил вроде все как описано

      1. Артем 07 марта 2023, 13:48 # 0

        Такое сообщение отправляется, если не отправлена переменная submitVar. Нужно, чтобы в форме присутствовала либо <button type="submit" name="sendSignin" value="1">, либо <input type="hidden" name="sendSignin" value="1">

      2. Сергей Шумков 07 марта 2023, 13:52 # 0

        Спасибо, подставил, теперь наоборот пишет что: Форма содержит ошибки.

        1. Артем 07 марта 2023, 13:54 # 0

          А вот это уже проблема валидации. Смотри, что выдает сервер, какие там ошибки.

        2. Сергей Шумков 07 марта 2023, 14:30 # 0

          прошу прощения, теперь выдает ошибки в консоли: Failed to load resource: the server responded with a status of 500 ()

          .../public_html/core/model/modx/modx.class.php 1772 Processor .../public_html/core/model/modx/processors/security/user/login.php does not exist; Array ( [processors_path] => .../public_html/core/model/modx/processors/security/ )

          1. Артем 07 марта 2023, 15:31 # 0

            MODX 3-й что ли? Если этого стандартного процессора нет, то что-то не так с путями, либо не та версия MODX.

            1. Сергей Шумков 07 марта 2023, 15:46 # 0

              Modx 2.8.4-pl (.../) скрыл просто полный путь папки проекта, nda

          2. Сергей Шумков 07 марта 2023, 16:04 # 0

            public_html/core/model/modx/processors/security/user/login.php по этому пути и правда нет этого вайла login.php

            public_html/core/model/modx/processors/security/login.class.php по этому пути есть такой только файл, Интересно как так может быть, файл точно не перемешал и не удалял, прам точно

            1. Артем 07 марта 2023, 16:07 # 0

              Значит нужно сделать runProcessor('login'..., а не runProcessor('security/login'...

            2. Сергей Шумков 07 марта 2023, 16:27 # 0

              Да кажется заработало, Огромное спасибо что помогли найти решение ошибок!

              1. Pinul Artem 31 августа 2023, 23:01 # 0

                А не подскажете что может быть..? У меня на сайте при оформлении заказа, получаю ошибку вида /core/components/formit/src/FormIt/Hook/Email.php : 322) С не возможностью отправки письма на почту.

                1. Артем 01 сентября 2023, 04:15 # 0

                  Если при вызове FormIt все параметры указаны верно и на локальной машине все отправляется, то проверьте последовательно:

                  ? Почтовые настройки modx на рабочем сайте (способ отправки, настройки smtp, логин/пароль, порт, протокол, если отправка идет через smtp). Если там все в порядке, идем далее. Если не в порядке — читайте детальное описание к вашему smtp серверу, как правильно указывать настройки. Иногда проблема может быть в адресе сервера, порте и протоколе tls

                  ? Проверьте почтовые логи сервера (/var/log/mail и т. п. в зависимости от операционной системы) — там как правило содержится подробная информация, почему письмо не хочет отправляться.

                  ? Проверьте, уходят ли в принципе письма с вашего сервера. Для этого просто попробуйте сделать простой php скрипт с функцией mail() или через команду sendmail в командной строке сервера.

                  ? Если у вас виртуальный хостинг (не VDS/VPS), то там как правило, самый быстрый способ найти проблему — это написать в техподдержку, так как у них много клиентов и если проблема частая, то ответ приходит очень быстро.

                  Удачи в поисках!

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

                Мы используем куки на нашем сайте. Продолжая просмотр, вы соглашаетесь с условиями пользовательского соглашения
                Пожалуйста, подождите. Процесс оформления заказа может занимать до 30 секунд.