Пропустим установку и настройку sfDoctrineGuardPlugin, она хорошо описана в документации к плагину. Наша задача — вынести форму авторизации в отдельный компонент. Для определенности будем считать, что все действия мы делаем в приложении frontend. Сделать компонент очень просто: создаем класс sfGuardAuthComponents, пишем контроллер компонента signin, и три шаблона - вспомогательный signin, который принимает решение о том, что выводить пользователю - форму авторизации, или меню авторизованного пользователя (Здравствуйте, %username%! Выход.), и два основных - собственно форма авторизации и меню авторизованного пользователя. Итак, начнем.
Создадим файл apps/frontend/modules/sfGuardAuth/actions/components.class.php со следующим содержимым:
<?php class sfGuardAuthComponents extends sfComponents { function executeSignin() { $class = sfConfig::get('app_sf_guard_plugin_signin_form', 'sfGuardFormSignin'); $this->form = new $class(); } } ?>
Контроллер компонента готов. Теперь нужно сделать три шаблона.
apps/frontend/modules/sfGuardAuth/templates/_signin.php
<?php if ($sf_user->isAuthenticated()): ?> <?php include_partial('sfGuardAuth/signin_auth_yes') ?> <?php else: ?> <?php include_partial('sfGuardAuth/signin_auth_no',array('form'=>$form)) ?> <?php endif ?>
Этот шаблон всего лишь решает, что вывести пользователю, в зависимости от того, авторизован тот или нет. Теперь сделаем шаблон _signin_auth_no.php, который выводит форму авторизации:
<script> $(function(){ $("#signinForm").ajaxForm({ url: '<?php echo url_for('@sf_guard_signin') ?>', type: 'post', dataType: 'json', beforeSubmit: function(){ $("#signinSubmit").attr("disable",true); $("#signinLoader").show(); }, success: function(data) { $("#signinSubmit").attr("disable",false); $("#signinLoader").hide(); if (data=='error') { //выводим сообщение об ошибке alert('Неверное имя пользователя или пароль'); } else if (data=='ok') { //Заменям форму авторизации на меню авторизованного пользователя // //Или просто обновляем страницу document.location.reload(); } else { alert('Неизвестная ошибка. Обратитесь к администрации'); } } }) }) </script> <form action="<?php echo url_for('@sf_guard_signin') ?>" method="post" id="signinForm"> <a href="<?php echo url_for('@sf_guard_password') ?>">Забыли пароль?</a> <?php echo $form->renderHiddenFields()?> <?php echo $form['username']->renderError() ?> <?php echo $form['password']->renderError() ?> <span>Логин</span> <?php echo $form['username']->render() ?> <span>Пароль:</span> <?php echo $form['password']->render() ?> <input name="" class="buton" value="" type="submit" id="signinSubmit"/> <img src="/images/loader.gif" style="padding-left:10px;display:none;" id="signinLoader"> </form>
Этот шаблон нуждается в подробном изучении. В шаблоне мы подготовили клиентскую часть для AJAX-авторизации: AJAX-изировали форму авторизации, написали обработчики для удачной и неудачной авторизации. Хочу обратить внимание на jQuery-плагин, который я здесь использую — jQuery Form Plugin. Этот плагин позволяет очень просто модифицировать любые формы (в том числе, содержащие input file) таким образом, что они отправляются с помощью XmlHttpRequest, и обрабатывать результат отправки. Вкратце остановлюсь на использовании плагина. Делаем совершенно обычную форму, затем вызываем $('форма').ajaxForm(опции). Вуаля! Форма готова к AJAX-отправке. Здесь не забываем добавить подключение jQuery-плагина в файл apps/frontend/config/view.yml
default: javascripts: [jquery/jquery_forms.js]
Теперь напишем обработчик AJAX-запроса (контроллер модуля sfGuardAuth, который примет AJAX-запрос, попытается авторизовать пользователя, и, либо отправит сообщение о неверной авторизации, либо о том, что авторизация прошла успешно. Javascript в шаблоне, который мы только что написали, получает ответ, и реагирует на него в зависимости от присланных данных (data). В этом примере реакция максимально примитивна - в случае успеха страница перезагружается (после перезагрузки будет показываться уже не форма авторизации, а меню авторизованного пользователя), а в случае неверного логина-пароля выскакивает alert(). Итак, контроллер, обрабатывающий AJAX-запрос на авторизацию. Придется скопировать и изменить соответствующий экшен модуля sfGuardAuth плагина sfDoctrineGuardPlugin. Создаем файл apps/frontend/modules/sfGuardAuth/actions.class.php со следующим содержимым:
<?php require_once(dirname(__FILE__)."/../../../../../plugins/sfDoctrineGuardPlugin/modules/sfGuardAuth/lib/BasesfGuardAuthActions.class.php"); /** * * @package symfony * @subpackage plugin * @author Evgeny Babin <psylosss@gmail.com> * @version */ class sfGuardAuthActions extends BasesfGuardAuthActions { public function executeSignin($request) { $user = $this->getUser(); if ($user->isAuthenticated()) { return $this->redirect('@homepage'); } $class = sfConfig::get('app_sf_guard_plugin_signin_form', 'sfGuardFormSignin'); $this->form = new $class(); if ($request->isMethod('post')) { $this->form->bind($request->getParameter('signin')); if ($this->form->isValid()) { $values = $this->form->getValues(); $this->getUser()->signin($values['user'], array_key_exists('remember', $values) ? $values['remember'] : false); if ($request->isXmlHttpRequest()) { return $this->renderText(json_encode('ok')); } // always redirect to a URL set in app.yml // or to the referer // or to the homepage $signinUrl = sfConfig::get('app_sf_guard_plugin_success_signin_url', $user->getReferer($request->getReferer())); //$signinUrl = $user->getReferer($request->getReferer()); return $this->redirect('' != $signinUrl ? $signinUrl : '@homepage'); } else { if ($request->isXmlHttpRequest()) { return $this->renderText(json_encode('error')); } } } else { // if we have been forwarded, then the referer is the current URL // if not, this is the referer of the current request $user->setReferer($this->getContext()->getActionStack()->getSize() > 1 ? $request->getUri() : $request->getReferer()); $module = sfConfig::get('sf_login_module'); if ($this->getModuleName() != $module) { return $this->redirect($module.'/'.sfConfig::get('sf_login_action')); } $this->getResponse()->setStatusCode(401); } } }
Мы несколько изменили логику поведения экшена. Теперь, если он вызывается методом post (отправлена форма), то экшен дополнительно проверяет, а не AJAX-ом ли запрошена авторизация? Если да, то выдает JSON-ответ: 'error', если форма невалидная, и 'ok', если форма валидная. Именно этот ответ видит и понимает javascript в шаблоне _signin_auth_no.php.
Осталось совсем чуть-чуть: написать шаблон авторизованного пользователя _signin_auth_yes.php:
Вы вошли как <b><?php echo $sf_user->getGuardUser()->username ?></b> <br> <a href="<?php echo url_for('@sf_guard_signout') ?>">Выход</a>
Вот и готово. Используем в любом шаблоне:
<?php include_component('sfGuardAuth','signin') ?>
Полезная ссылка: генератор gif-иконок AJAX-загрузки
Спасибо, отличный пост.
ОтветитьУдалитьЕдинственный нюанс - яваскрипт хорошо бы сделать unobtrusive. Но это уже придирки :)
Теперь сделаем шаблон _signin_auth_no.yml
ОтветитьУдалитьnenuzhno li zdes _signin_auth_no.php ?
@develop7, яваскрипт, безусловно, поддается шлифовке :)
ОтветитьУдалить@Malas, спасибо, поправил :)
Доброго времени суток! пожалуйста опишите более подробно(на пальцах:) для чайников:b)
ОтветитьУдалить