пятница, 18 апреля 2008 г.

Проверка формы

Проверка формы Login

Валидационный файл

Создаем login.yml в /frontend/modules/user/validate:



methods:
post: [nickname, password]

names:
nickname:
required: true
required_msg: your nickname is required
validators: nicknameValidator

password:
required: true
required_msg: your password is required

nicknameValidator:
class: sfStringValidator
param:
min: 5
min_error: nickname must be 5 or more characters

public function handleError()

{

return sfView::ERROR;

}


That's a whole new template to write. But we'd rather display the login form again, with the error messages displayed close to the problematic fields. So let's modify the login error behaviour to display, in this case, the loginSuccess.php template:


public function handleErrorLogin()

{

return sfView::SUCCESS;

}


The naming conventions that link the action name, its return value and the template file name are exposed in the view chapter of the symfony book.


Шаблон хелпера error


При повторном вызове loginSuccess.php необходимо выводить сообщение об ошибке. Изменим две строки формы на:


<?php use_helper('Validation') ?>



<div class="form-row">

<?php echo form_error('nickname') ?>

<label for="nickname">nickname:</label>

<?php echo input_tag('nickname', $sf_params->get('nickname')) ?>

</div>



<div class="form-row">

<?php echo form_error('password') ?>

<label for="password">password:</label>

<?php echo input_password_tag('password') ?>

</div>



Стили ошибок


Определим класс .form_error в web/main.css:


.form_error

{

padding-left: 85px;

color: #d8732f;

}


Авторизация пользователя


Редактируем login.yml:


...
...
names:
nickname:
required: true
required_msg: your nickname is required
validators: [nicknameValidator, userValidator]
...
userValidator:
class: myLoginValidator
param:
password: password
login_error: this account does not exist or you entered a wrong password

Хранение пароля


Меняем schema.xml:


<column name="email" type="varchar" size="100" />

<column name="sha1_password" type="varchar" size="40" />

<column name="salt" type="varchar" size="32" />


Перестраиваем модель Добавляем в/lib/model/User.php метод setPassword():


public function setPassword($password)

{

$salt = md5(rand(100000, 999999).$this->getNickname().$this->getEmail());

$this->setSalt($salt);

$this->setSha1Password(sha1($salt.$password));

}


Добавим пароль в тестовые данные


/data/fixtures/test_data.yml:



User:
...
fabien:
nickname: fabpot
first_name: Fabien
last_name: Potencier
password: symfony
email: fp@example.com

francois:
nickname: francoisz
first_name: François
last_name: Zaninotto
password: adventcal
email: fz@example.com

$ php batch/load_data.php


Напишем myLoginValidator. Его можно создать в любой директории lib/ (/lib/, /apps/frontend/lib/,/apps/frontend/modules/user/lib/). Например создадим myLoginValidator.class.php в /apps/frontend/lib/:


<?php



class myLoginValidator extends sfValidator

{

public function initialize($context, $parameters = null)

{

// initialize parent

parent::initialize($context);



// set defaults

$this->setParameter('login_error', 'Invalid input');



$this->getParameterHolder()->add($parameters);



return true;

}



public function execute(&$value, &$error)

{

$password_param = $this->getParameter('password');

$password = $this->getContext()->getRequest()->getParameter($password_param);



$login = $value;



// anonymous is not a real user

if ($login == 'anonymous')

{

$error = $this->getParameter('login_error');

return false;

}



$c = new Criteria();

$c->add(UserPeer::NICKNAME, $login);

$user = UserPeer::doSelectOne($c);



// nickname exists?

if ($user)

{

// password is OK?

if (sha1($user->getSalt().$password) == $user->getSha1Password())

{

$this->getContext()->getUser()->setAuthenticated(true);

$this->getContext()->getUser()->addCredential('subscriber');



$this->getContext()->getUser()->setAttribute('subscriber_id', $user->getId(), 'subscriber');

$this->getContext()->getUser()->setAttribute('nickname', $user->getNickname(), 'subscriber');



return true;

}

}



$error = $this->getParameter('login_error');

return false;

}

}



Изменим:


public function executeLogin()

{

if ($this->getRequest()->getMethod() != sfRequest::POST)

{

// display the form

$this->getRequest()->getParameterHolder()->set('referer', $this->getRequest()->getReferer());



return sfView::SUCCESS;

}

else

{

// handle the form submission

// redirect to last page

return $this->redirect($this->getRequestParameter('referer', '@homepage'));

}

}



Запрет доступа

/apps/frontend/modules/question/config/security.yml :


add:
is_secure: on
credentials: subscriber

all:
is_secure: off

Оптимизация


Добавим метод в /apps/frontend/lib/myUser.php :


public function signIn($user)

{

$this->setAttribute('subscriber_id', $user->getId(), 'subscriber');

$this->setAuthenticated(true);



$this->addCredential('subscriber');

$this->setAttribute('nickname', $user->getNickname(), 'subscriber');

}



public function signOut()

{

$this->getAttributeHolder()->removeNamespace('subscriber');



$this->setAuthenticated(false);

$this->clearCredentials();

}


Изменим 4 строки начиная с $this->getContext()->getUser() в myLoginValidator классе на:


$this->getContext()->getUser()->signIn($user);


Изменим user/logout децствие на:


public function executeLogout()

{

$this->getUser()->signOut();



$this->redirect('@homepage');

}


В классе myUser добавим метод:


public function getSubscriberId()

{

return $this->getAttribute('subscriber_id', '', 'subscriber');

}



public function getSubscriber()

{

return UserPeer::retrieveByPk($this->getSubscriberId());

}



public function getNickname()

{

return $this->getAttribute('nickname', '', 'subscriber');

}


Используем его в layout.php:

сменив

<li><?php echo link_to($sf_user->getAttribute('nickname', '', 'subscriber').' profile', 'user/profile') ?></li>



на

<li><?php echo link_to($sf_user->getNickname().' profile', 'user/profile') ?></li>



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