[СДЕЛАЙ САМ] Ajax Регистрация, Авторизация, Сброс пароля, Редактирование профиля
Задача: сделать ajax регистрацию, авторизацию, сброс пароля и редактирование пользователя, используя минимум сторонних компонентов.
ИСПОЛЬЗУЙТЕ КОМПОНЕНТ SENDIT
Почему минимум? Ну часть из тех компонентов, что реализуют подобный функционал, платная (Office, ajaxLogin) и бюджеты есть не всегда на них есть. Некоторые (ajaxLogin) в данный момент не доступны из-за смерти автора. Общий недостаток большинства компонентов это то, что они загружают дополнительные скрипты и стили, что порой приводит к необходимости дополнительно оптимизировать сайт. Компонент Login не работает по ajax. Однако это можно обойти , но runSnippet запустит много всего и не факт что это всё нужно в данный момент. Поэтому предлагаю своё решение.
Нам понадобится:
1. AjaxForm;
2. FormIt;
3. Этот репозиторий.
Порядок действий:
1. Скопировать core/elements/snippets/ajaxidentification.class.php.
2. Создать в админке сниппеты
2.1 AjaxIdentification (код лежит в core/elements/snippets/hooks/AjaxIdentification.php);
2.2 userExists (код лежит в core/elements/snippets/validators/userExists.php);
2.3 userNotExists (код лежит в core/elements/snippets/validators/userNotExists.php;
2.4 ActivateUser (код лежит в core/elements/snippets/ActivateUser.php) // этот можно вызывать прям из файла если хотите.
3. В вывоз AjaxForm в параметр hooks первым значением добавить AjaxIdentification, сюда же добавить параметр method ( register — регистрация, login — авторизация, forgot — восстановление доступа, update — обновление данных).
4. В js на событие af_complete добавить редирект на нужные страницы. Ссылки можно получать
из мета-тегов с именами типа loginSuccessUrl.
Всё. Далее немного потока сознания и пояснений.
Делать редирект после регистрации или авторизации, передавая ссылку через мета-тег, мне кажется неудобным. Поскольку AjaxForm, к сожалению, не предоставляет простого способа изменить класс обработчик, как это сделано в miniShop2, нужно немного подправить исходники. А именно нужно заменить в ajaxform.class.php метод handleFormit() на код приведённый ниже
Теперь немного о классе AjaxIdentification. Я хотел использовать процессоры и только их, но так и не смог решить проблему с правами доступа для процессора security/user/update.Поэтому метод update работает без процессора.
Поля extended должны иметь в имени префикс extended_ или любой другой, но тогда в вызов нужно добавить параметр extendedFieldPrefix со значением префикса.
Если требуется ручная проверка аккаунта перед предоставлением доступа, укажите в вывозе параметр moderate со значением true.
Если требуется подтверждение почты и активация пользователя только после этого укажите параметр activation=1, при этом в $_POST должен быть указан email, а параметр moderate должен быть false. Так же в вызов нужно добавить второй хук FormItAutoResponder. Время действия ссылки можно передать в параметре activationUrlTime в секундах. По умолчанию 10800 секунд или 3 часа. Значение id ресурса на который будет вести ссылка активации из письма можно передать в параметре activationResourceId, по умолчанию 1.
Плавно переходим к сниппету ActivateUser. Его нужно вызывать на странице активации. Он вернёт true если пользователь активирован и false в противном случае. Дальнейшие действия на ваше усмотрение.
Далее два валидатора, которые применяются к полю из которого берётся username ( параметр usernameField, по умолчанию username):
1. userExists возвращает true если пользователь НЕ существует. Этот валидатор используется при регистрации.
2. userNotExists возвращает true если пользователь существует. Это валидатор используется при восстановлении пароля, чтобы не отправлять письмо несуществующим пользователя.
Ещё немного о параметрах.
'authenticateContexts' — список контекстов разделённых запятыми в которые нужно авторизовать пользователя.
'passwordField' — имя поля с паролем, по умолчанию password.
'autoLogin' — если true и не нужна активация и модерация пользователь после регистрации будет авторизован, по умолчанию false.
'usergroups' — список id групп разделенный запятыми, в которые следует добавить пользователя при регистрации.
'usergroupsField' — позволяет пользователю самостоятельно выбрать группы, если данный параметр указан, предыдущий будет проигнорирован.
В двух последних параметрах допустима запись вида '2:1:0,3:1:1', где первое число это id группы, второе id роли ( по умолчанию 0 — superuser, 1 — member), третье rank — не знаю для чего, но в процессоре было, я оставил.
В репозитории есть примеры всех вызовов и чанков, в том числе и писем.
Напоследок, сам репозиторий это форк с AjaxForm из которого я выпилил jQuery, переписал весь js и ещё кое-что. Кому интересно читайте тут .
ИСПОЛЬЗУЙТЕ КОМПОНЕНТ SENDIT
Почему минимум? Ну часть из тех компонентов, что реализуют подобный функционал, платная (Office, ajaxLogin) и бюджеты есть не всегда на них есть. Некоторые (ajaxLogin) в данный момент не доступны из-за смерти автора. Общий недостаток большинства компонентов это то, что они загружают дополнительные скрипты и стили, что порой приводит к необходимости дополнительно оптимизировать сайт. Компонент Login не работает по ajax. Однако это можно обойти , но runSnippet запустит много всего и не факт что это всё нужно в данный момент. Поэтому предлагаю своё решение.
Нам понадобится:
1. AjaxForm;
2. FormIt;
3. Этот репозиторий.
Порядок действий:
1. Скопировать core/elements/snippets/ajaxidentification.class.php.
2. Создать в админке сниппеты
2.1 AjaxIdentification (код лежит в core/elements/snippets/hooks/AjaxIdentification.php);
2.2 userExists (код лежит в core/elements/snippets/validators/userExists.php);
2.3 userNotExists (код лежит в core/elements/snippets/validators/userNotExists.php;
2.4 ActivateUser (код лежит в core/elements/snippets/ActivateUser.php) // этот можно вызывать прям из файла если хотите.
3. В вывоз AjaxForm в параметр hooks первым значением добавить AjaxIdentification, сюда же добавить параметр method ( register — регистрация, login — авторизация, forgot — восстановление доступа, update — обновление данных).
4. В js на событие af_complete добавить редирект на нужные страницы. Ссылки можно получать
из мета-тегов с именами типа loginSuccessUrl.
Всё. Далее немного потока сознания и пояснений.
Делать редирект после регистрации или авторизации, передавая ссылку через мета-тег, мне кажется неудобным. Поскольку AjaxForm, к сожалению, не предоставляет простого способа изменить класс обработчик, как это сделано в miniShop2, нужно немного подправить исходники. А именно нужно заменить в ajaxform.class.php метод handleFormit() на код приведённый ниже
public function handleFormIt(array $scriptProperties = array())
{
$plPrefix = isset($scriptProperties['placeholderPrefix'])
? $scriptProperties['placeholderPrefix']
: 'fi.';
$errors = array();
foreach ($scriptProperties['fields'] as $k => $v) {
if (isset($this->modx->placeholders[$plPrefix . 'error.' . $k])) {
$errors[$k] = $this->modx->placeholders[$plPrefix . 'error.' . $k];
}
}
if (!empty($this->modx->placeholders[$plPrefix . 'error.recaptcha'])) {
$errors['recaptcha'] = $this->modx->placeholders[$plPrefix . 'error.recaptcha'];
}
if (!empty($this->modx->placeholders[$plPrefix . 'error.recaptchav2_error'])) {
$errors['recaptcha'] = $this->modx->placeholders[$plPrefix . 'error.recaptchav2_error'];
}
if (!empty($errors)) {
$message = !empty($this->modx->placeholders[$plPrefix . 'validation_error_message'])
? $this->modx->placeholders[$plPrefix . 'validation_error_message']
: 'af_err_has_errors';
$status = 'error';
} else {
$message = isset($scriptProperties['successMessage'])
? $scriptProperties['successMessage']
: 'af_success_submit';
$status = 'success';
// вот что я добавил
if($scriptProperties['redirectId']){
$redirectUrl = $this->modx->makeUrl($scriptProperties['redirectId'], '', '', 'full');
$errors['redirectUrl'] = $redirectUrl;
$errors['redirectTimeout'] = $scriptProperties['redirectTimeout'] ?: 2000;
}
}
return $this->$status($message, $errors);
}
Эта манипуляция позволит в js на событие af_complete в массиве response.data получить два параметра redirectUrl (ссылка для перехода) и redirectTimeout (время задержки до перехода для функции setTimeout). Сами данные мы будем передавать через вызов AjaxForm в параметрах redirectId (id ресурса для перехода) и redirectTimeout.Теперь немного о классе AjaxIdentification. Я хотел использовать процессоры и только их, но так и не смог решить проблему с правами доступа для процессора security/user/update.Поэтому метод update работает без процессора.
Поля extended должны иметь в имени префикс extended_ или любой другой, но тогда в вызов нужно добавить параметр extendedFieldPrefix со значением префикса.
Если требуется ручная проверка аккаунта перед предоставлением доступа, укажите в вывозе параметр moderate со значением true.
Если требуется подтверждение почты и активация пользователя только после этого укажите параметр activation=1, при этом в $_POST должен быть указан email, а параметр moderate должен быть false. Так же в вызов нужно добавить второй хук FormItAutoResponder. Время действия ссылки можно передать в параметре activationUrlTime в секундах. По умолчанию 10800 секунд или 3 часа. Значение id ресурса на который будет вести ссылка активации из письма можно передать в параметре activationResourceId, по умолчанию 1.
Плавно переходим к сниппету ActivateUser. Его нужно вызывать на странице активации. Он вернёт true если пользователь активирован и false в противном случае. Дальнейшие действия на ваше усмотрение.
Далее два валидатора, которые применяются к полю из которого берётся username ( параметр usernameField, по умолчанию username):
1. userExists возвращает true если пользователь НЕ существует. Этот валидатор используется при регистрации.
2. userNotExists возвращает true если пользователь существует. Это валидатор используется при восстановлении пароля, чтобы не отправлять письмо несуществующим пользователя.
Ещё немного о параметрах.
'authenticateContexts' — список контекстов разделённых запятыми в которые нужно авторизовать пользователя.
'passwordField' — имя поля с паролем, по умолчанию password.
'autoLogin' — если true и не нужна активация и модерация пользователь после регистрации будет авторизован, по умолчанию false.
'usergroups' — список id групп разделенный запятыми, в которые следует добавить пользователя при регистрации.
'usergroupsField' — позволяет пользователю самостоятельно выбрать группы, если данный параметр указан, предыдущий будет проигнорирован.
В двух последних параметрах допустима запись вида '2:1:0,3:1:1', где первое число это id группы, второе id роли ( по умолчанию 0 — superuser, 1 — member), третье rank — не знаю для чего, но в процессоре было, я оставил.
В репозитории есть примеры всех вызовов и чанков, в том числе и писем.
Напоследок, сам репозиторий это форк с AjaxForm из которого я выпилил jQuery, переписал весь js и ещё кое-что. Кому интересно читайте тут .
Поблагодарить автора
Отправить деньги
Комментарии: 26
3. AjaxForm+Register — я так делал, способ простой, но грубый.Теперь есть сложный и еще грубее, поздравляю!
Умный в гору не пойдет, умный гору обойдет!Какая-то непонятная инструкция, какие-то непонятные манипуляции с исходниками. Только из статьи понятно, что это ajax регистрация/авторизация, а должно быть в заголовке.
Советую потратить побольше времени и сделать нормальный компонент.
Спасибо, действительно забыл в заголовке про Ajax. И потрачу больше времени и сделаю компонент.
Не ошибается тот, кто ничего не делает.
Рад, что нормально воспринимаешь критику.
Рад, что нормально воспринимаешь критику.
Я ради критики сюда это и выкладываю. Иначе сложно понять, где я косячу. Жаль что, подробные разборы моего кода бывают редко, но это объяснимо. С миру по нитки что-нибудь сошью)))
Артур, ты если ради критики выкладываешь — то лучше бы это делать в разделе вопросы.
Раздел готовые решения предполагает собственно готовое решение. Причем понятное случайному посетителю (хорошо бы).
Я три раза перечитал текст, но так и не понял какую задачу ты решал, в чем ее решение, и почему это решение такое. Просто поток мыслей — без какой-либо цели.
Раздел готовые решения предполагает собственно готовое решение. Причем понятное случайному посетителю (хорошо бы).
Я три раза перечитал текст, но так и не понял какую задачу ты решал, в чем ее решение, и почему это решение такое. Просто поток мыслей — без какой-либо цели.
Ты прав, изложил я свои мысли коряво. Поэтому заметку переписал полностью. Надеюсь теперь суть задачи и решение более очевидны.
Да по тексту стало сильно понятнее. Но по-прежнему не понятно зачем такой инструментарий использовать. Особенно при формулировке
Зачем сюда подключать твои здоровенные комбайны, да еще форкнутые, ума не приложу. Это ж изобретение велосипеда, которых тут на форуме наверное с несколько десятков наберется.
Ты бы лучше свою деятельность направил на реанимацию ajaxLogin
используя минимум сторонних компонентов.Куда более правильно было был написать малюсенький JS скрипт, который слушает форму, отправляет условные логин-пароль на сервер. А Сервер в свою очередь тоже, используя простенький PHP скрипт заводит запись в базе. Ну или логинит.
Зачем сюда подключать твои здоровенные комбайны, да еще форкнутые, ума не приложу. Это ж изобретение велосипеда, которых тут на форуме наверное с несколько десятков наберется.
Ты бы лучше свою деятельность направил на реанимацию ajaxLogin
Куда более правильно было был написать малюсенький JS скрипт, который слушает форму, отправляет условные логин-пароль на сервер. А Сервер в свою очередь тоже, используя простенький PHP скрипт заводит запись в базе. Ну или логинит.AjaxForm оно и есть, а FormIt реализует возможность валидации и отправки писем.
Зачем сюда подключать твои здоровенные комбайныЭто ты конечно мне польстил))) Здоровенный)))
Это ж изобретение велосипедаНе спорю и не навязываю. Мой велосипед не хуже других, так что пусть будет, мне на память.
Ты бы лучше свою деятельность направил на реанимацию ajaxLoginЯ работаю на комбайном форм, который совместит в себе AjaxForm, Quiz, Login и Formalicious. Постараюсь ближайшие месяцы закончить. А это временный вариант.
Может сделать раздел «Песочница». =)
Мне кажется «Готовые решения» и так отчасти песочница. Я же вот дал ссылку на репозиторий, копируй себе и твори что хочешь))) Другие тоже так или иначе выкладывают в этом разделе код, с которым можно делать что угодно.
2. ajaxLogin — платный и из-за смерти автора он более недоступен.Может я пропустил информацию об этом, но всё равно печально слышать такие новости, я про смерть автора…
Слишком много гемора!
Вот пример, JS + LOGIN (https://vectorserver.ru/test/ajaxform-login.html )
Вызов:
Вот пример, JS + LOGIN (https://vectorserver.ru/test/ajaxform-login.html )
Вызов:
[[!AjaxLogin_vectorserver? &snippet=`Login`]]
[[!AjaxLogin_vectorserver? &snippet=`Login` &id=`q`]]
[[!AjaxLogin_vectorserver? &snippet=`Register` &id=`123`]]
Код сниппета AjaxLogin_vectorserver:<?php
/* @global $modx*/
/** @var TYPE_NAME $scriptproperties */
/** @var TYPE_NAME $snippet */
/** @var TYPE_NAME $id */
$id = $id??$modx->resource-id;
$uniqid = "form_".md5($snippet.$id);
$url = $modx->resource->uri;
$js = "<script>
let $uniqid = document.getElementById('{$uniqid}').getElementsByTagName('form')[0];
if($uniqid){
$uniqid.addEventListener('submit', (e) => {
fetch($uniqid.action, {
method: 'POST',
body: new FormData($uniqid)
}).then(function (response) {
// The API call was successful!
return response.text();
}).then(function (data) {
// This is the HTML from our response
var parser = new DOMParser();
var doc = parser.parseFromString(data, \"text/html\");
$uniqid.innerHTML = doc.getElementById('{$uniqid}').innerHTML;
}).catch(function (err) {
// There was an error
console.warn('Something went wrong.', err);
});;
// on form submission, prevent default
e.preventDefault();
});
}
</script>";
$runSnippet = "<div id='{$uniqid}' class='AjaxLogin_vectorserver'>{$modx->runSnippet($snippet)}</div>\n{$js}";
return $runSnippet;
- &id: Уникальный ID, если есть конфликты форм
- &snippet:Login,ForgotPassword,UpdateProfile,Register
- &redirect:[[~1]]
- &chunkForm: имя чанка или html код (Для ForgotPassword,UpdateProfile,Register не используются в параметрах tpl, для этого сделан параметр)
А как показать уведомление? Как редирект сделать? Заполнение профиля работать будет? Если да, то после сохранения поля очистятся или нет?
Допилил редирект если он нужен:
Параметры:
Параметры:
//Login
[[!AjaxLogin_vectorserver? &snippet=`Login`]]
//ForgotPassword
[[!AjaxLogin_vectorserver?
&snippet=`ForgotPassword`
&id=`q`
&redirect=`[[~1]]`
]]
<h2>UpdateProfile</h2>
[[!AjaxLogin_vectorserver?
&snippet=`UpdateProfile`
&useExtended=`0`
&chunkForm=`[[$UProfile]]`
]]
Код сниппета:<?php
/* @global $modx*/
/** @var TYPE_NAME $scriptproperties */
/** @var TYPE_NAME $snippet */
/** @var TYPE_NAME $id */
$chunkForm = $chunkForm??'';
//Уникальный ID
$id = $id??$modx->resource->id;
$uniqid = "form_".md5($snippet.$id);
//Если нужен редирект
$redirect = $redirect??false;
//JS TMP
$js = "<script>
let $uniqid = document.getElementById('{$uniqid}').getElementsByTagName('form')[0];
if($uniqid){
$uniqid.addEventListener('submit', (e) => {
let redirectTo = '{$redirect}';
fetch($uniqid.action, {
method: 'POST',
body: new FormData($uniqid)
}).then(function (response) {
// The API call was successful!
return response.text();
}).then(function (data) {
// This is the HTML from our response
var parser = new DOMParser();
var doc = parser.parseFromString(data, \"text/html\");
$uniqid.innerHTML = doc.getElementById('{$uniqid}').innerHTML;
if(redirectTo){
window.location = '{$redirect}';
}
}).catch(function (err) {
// There was an error
console.warn('Something went wrong.', err);
});
// on form submission, prevent default
e.preventDefault();
});
}
</script>";
$runSnippet = "<div id='{$uniqid}' class='AjaxLogin_vectorserver'>{$modx->runSnippet($snippet)}{$chunkForm}</div>\n{$js}";
return $runSnippet;
Понятно. Можно проще. Не писать свой сниппет для отправки ajax а использовать AjaxForm где в параметре snippet передать имя своего сниппета, а в параметре, например, method передать название сниппета из компонента Login. Таким образом сохраняется функционал обоих компонентов и свой js можно не писать. Но я по-прежнему не уверен, что использовать runSnippet оптимальное решение.
Уведомления берутся стандартные из чанков LOGIN
Это прекрасно, а выводить их как? Прикручивать плагин или писать свой вариант для показа уведомлений?
За JS в PHP жирный минус. Зачем?! А главное Зачем?!
Это не готовое решение, а пример реализации!
Ну тогда уж приводите пример в чистом JS, тем более раз вы показываете в контексте «Как делать правильно»
Твой пример очень похож на вот этот, с той разницей, что пример по ссылке гораздо легче понять.
я думал хуже чем Артур сделать было нереально, но ты справился
Всё познаётся в сравнении)))
Я делал через Office+HybridAuth, только немного пришлось доработать обработчик на активацию
Думаю и сюда можно HybridAuth прикрутить, но у меня такой задачи не было.
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.