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

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

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

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

172
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 и использовать данный компонент для обработки любых форм.

Читать

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

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