...

вторник, 8 апреля 2014 г.

Авторизация через fancybox в yii

Статья о том, как прикрутить fancybox-авторизацию к проекту на yii в кодировке win-1251. Если вы оказались более счастливым разработчиком, и ваш проект в utf, можете просто пропускать пункты, относящиеся к encoding hell, остальное все так же. Хотя, возможно тогда вам и не понадобится эта статья.

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


Подключаем fancybox



Скачиваем расширение fancybox, кладем в папку extensions.

Подключаем в шаблоне:

<?php
$this->widget('application.extensions.fancybox.EFancyBox', array());
?>


Делаем в шаблоне ссылку, по которой будет вызываться наш fancybox:



<?php
echo CHtml::link('Войти', array('/some_controller/fancy/'), array('class'=>'fancy_auth'));
?>


По классу ссылки fancy_auth навешиваем событие:



$(document).ready(function(){
$(".fancy_auth").fancybox({
'transitionIn' : 'elastic',
'transitionOut' : 'elastic',
'width' : 345,
'height' : 360,
'autoDimensions': false,
'autoSize': false,
'speedIn' : '500',
'speedOut' : '500',
'type' : 'ajax',
'closeBtn' : false
});


В основном, параметры приведены для примера. Единственное, на что стоит обратить внимание — 'type': 'ajax'. Если вы сделаете 'type': 'iframe', не будет работать код обработки успешного запроса, который я привожу ниже, а именно — код перезагрузки страницы. Если после авторизации перезагрузка вам не нужна, выбирайте тип по своему усмотрению.


Контроллер



Как видно из параметров ссылки, представление, содержащее форму авторизации, отдается методом fancy контроллера some_controller. У меня этот метод выглядит так:


public function actionFancy()
{
$model=new UserLogin;
$this->performAjaxValidation($model);
echo $this->renderPartial('_login_utf',array('model'=>$model),true,true);
}


По умолчанию, значение последнего параметра у renderPartial — false. В данном случае, для нас важно выставить его в true, потому что он отвечает за обработку методом processOutput(), который в методе render вызывается и по умолчанию, и подключает все необходимые скрипты и прочее динамическое содержимое. Без этого у нас не будет работать обработка ошибок при регистрации.


Шаблон и немного encoding hell



Если вам повезло, и у вас проект на utf-8, просто создаете нужное представление. Например, так:


<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'user-login',
//отправляем данные экшену, отвечающему за авторизацию
'action' => Yii::app()->createUrl('/user/login'),
//включаем ajax-валидацию ошибок
'enableAjaxValidation'=>true,
'clientOptions'=>array(
'validateOnSubmit'=>true,
//назначаем js функцию, которой нужно передать управление после того, как пришел ответ.
//более подробные пояснения и код функции будут приведены ниже
'afterValidate' => 'js:afterValidate',
),
)); ?

<?php echo $form->labelEx($model,'username'); ?>
<?php echo $form->textField($model,'username'); ?>
<?php echo $form->error($model,'username'); ?>

<?php echo $form->labelEx($model,'password'); ?>
<?php echo $form->passwordField($model,'password'); ?>
<?php echo $form->error($model,'password'); ?>

<?php echo CHtml::SubmitButton('Войти и скачать', array(
'type' => 'POST',
// Результат запроса записываем в элемент, найденный
// по CSS-селектору #msg.
'update' => '#msg',
'class'=>'journalFancySubmit',
)); ?>
<?php $this->endWidget(); ?>


Если все очень печально, и ваш проект на win-1251, как и мой, то ваш шаблон отобразится квадратиками, то есть не в той кодировке. Холливарщики скажут — переделывайте срочно в utf, и будут правы, но к сожалению, часто реалии таковы, что по тем или иным причинам перенести весь проект в религиозно верную кодировку нельзя, а чтоб работало — надо. Самым простым костылем мне показалось просто сделать сам файл шаблона в кодировке utf-8. Тогда все отдается корректно.


Обработка ajax-валидации в контроллере, снова проблемы в кодировкой



Для того, чтобы контроллер корректно работал с установленной вами ajax-валидацией, нужно добавить обработку ajax-запроса в контроллере, обычно это делается так:


if (isset($_POST['ajax']) && $_POST['ajax'] === 'login-form') {
echo CActiveForm::validate($model);
Yii::app()->end;
}



Но в случае win-1251 мы получим ошибку, поскольку json_encode, вызывающаяся в конце для возвращения результата валидации не хочет работать с этой кодировкой. Нужно переписать метод validate:




protected function validate($models, $attributes=null, $loadInput=true)
{
$result=array();
if(!is_array($models))
$models=array($models);
foreach($models as $model)
{
if($loadInput && isset($_POST[get_class($model)]))
$model->attributes=$_POST[get_class($model)];
$model->validate($attributes);
foreach($model->getErrors() as $attribute=>$errors)
$result[CHtml::activeId($model,$attribute)]=$errors;
}

if (empty($result)) {
$utf_result = array();
}

foreach ($result as $key => $value) {
if (is_array($value)) {
foreach ($value as $inner_key => $inner_value) {
$utf_result[$key][$inner_key] = iconv('windows-1251', 'UTF-8', $inner_value);
}
} else {
$utf_result[$key] = iconv('windows-1251', 'UTF-8', $value);
}
}

return function_exists('json_encode') ? json_encode($utf_result) : CJSON::encode($utf_result);
}


Здесь скопирован метод CActiveForm::validate и в конце добавлена перекодировка $result.


Соответственно, меняем вызов




echo CActiveForm::validate($model);




на


echo $this->validate($model);


Теперь стандартная обработка ошибок будет работать корректно.


После успешной авторизации



Авторизация прошла успешно, теперь самое время вспомнить о js-функции afterValidate, которую мы подключали в clientOptions при создании виджета формы авторизации:


'clientOptions'=>array(
'validateOnSubmit'=>true,
'afterValidate' => 'js:afterValidate',


afterValidate — функция, которая будет вызвана после выполнения ajax-проверки.


Входящие параметры — (data, hasError), form — JQuery представление объекта формы, data — json-ответ от сервера, HasError — булевское значение, указывающее, были ли ошибки при валидации.

Имейте ввиду, afterValidate доступно только если validateOnSubmit установлена ​​в истину.


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


Например, у меня она выглядит примерно так:



function afterValidate(form, data, hasError) {
if (hasError == false) {
window.location.reload();
parent.$.fancybox.close();
}
}


Источники



Все решения взяты с yii-форума и stackoverflow.com и просто просуммированы в статье.
Вместо заключения



Желаю вам и себе работать только с проектами в utf-8 и радоваться жизни.

This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Комментариев нет:

Отправить комментарий