Briefly in English
Next part of tutorial on using Kohana 3 Jelly and Jelly-Auth (autologin, built-in role system application). Will be translated soon.
1. вместо
[code lang="php"]
$this->auth = Jelly_Auth::instance();
[/code]
лучше
[code lang="php"]
$this->auth = Auth::instance();
[/code]
Thanks SpadXIII
2. модуль ORM здесь действительно не нужен и его можно спокойно отключить (спасибо Sezarin).
3. Для удобства можно ввести свойство Controller_admin::$user и определять его в before():
[code lang="php"]
$this->user = $this->auth->get_user();
[/code]
3. В описании поля email модели стоит только проверка на уникальность, но нет проверки на пустое поле. Поэтому если кто-то не указал электронную почту, а потом это же делает другой, то выбрасывается Database Exception на неуникальность полей под индексом UNIQUE (которое не ловится, поскольку стоит catch на Validation_Exception). Я не нашел лучшего способа исправить ситуацию, кроме как наследовать User, переопределив метод initialize() таким образом (если нет желания переписать в нем все поля полностью):
[code lang="php"]
public static function initialize(Jelly_Meta $meta)
{
$meta->fields = array(
'email' => new Field_Email(array(
'unique' => TRUE,
'rules' => array(
'not_empty' => array(TRUE),
)
)),
);
parent::initialize($meta);
}
[/code]
Кроме того, был малость исправлен и дополнен вывод сообщений об ошибках при валидации.
Сделаем автологин.
Для этого нужно
а) изменить форму, добавив чекбокс
б) добавить на страницу логина обработку чекбокса, переписав проверку $_POST таким образом
[code lang="php"]
// try to login
if ($_POST)
{
$username = $_POST['username'];
$password = $_POST['password'];
$remember = isset($_POST['remember']) ? TRUE : FALSE;
if ($this->auth->login($username, $password, $remember))
{
Request::instance()->redirect('admin/index');
} else {
$errors = array('Login or password incorrect');
}
}
[/code]
в) переписать защищенные методы с учетом включенного автологина. В моем случае пришлось проверять право на просмотр страницы с помощью $this->auth->logged_in('login'), что автоматически пытается заавтологинить юзера.
Для реализации простейшей ролевой системы вполне пригоден имеющийся в модуле Jelly-Auth функционал -- метод has_role($role). Например, разрешим добавлять пользователя только администратору. Однако для этого нужно предоставить возможность назначать роли пользователям.
Надо
а) в методе контроллера action_users() в ветке 'edit' добавить переменные, содержащие коллекцию ролей системы и массив активных ролей пользователя:
[code lang="php"]
$roles = Jelly::select('roles')
->execute();
...
if ($is_saved)
{
$this->template->content = 'User profile was updated';
} else {
// output user profile form
$this->template->content = $content
->set('id', $user->id)
->set('username', $user->username)
->set('email', $user->email)
->set('user_roles', $user->roles->as_array())
->set('roles', $roles);
}
[/code]
б) соответственно, в форме ('views/admin/edit_user') нужно вставить массив чекбоксов типа
[code lang="php"]
Assigned roles
-
<?php echo Form::checkbox('roles[]', $role['id'], in_array($role['id'], $role_ids), array('id' => 'roles_'.$role['id'])).' '
.Form::label('roles_'.$role['id'], $role['name'].'
'.$role['description']);?>
<?php
$role_ids = array();
foreach ($user_roles as $ur)
{
$role_ids[] = $ur['id'];
}
foreach ($roles as $role)
{
?>
<?
}
?>
[/code]
Первый foreach выглядит не очень красиво, но я в силу неопытности не нашел лучшего способа извлечь массив role IDs из ассоциативного массива.
в) Остается обработать приходящий в POST массив номеров ролей:
[code lang="php"]
$user->roles = isset($_POST['roles']) ? $_POST['roles'] : array();
[/code]
Далее можем, например, разрешить добавление нового пользователя только админу
[code lang="php"]
if ($this->user->has_role('admin'))
...
[/code]
Увы, хранение данных пользователя в сессии приводит к тому, что внесенные изменения вступают в силу после перелогина.
Разумеется, такая простая ролевая система может помочь только в несложных случаях. Поэтому буду думать над продолжением.
Скачать / Download 100 (zipped ~11 KiB)
Комментариев: 6 RSS
1 Sezarin 23-04-2010 19:46
Неплохой пример реализации сложных вещей просто...
Я думаю, у Jelly - большое будущее.
Кстати, со вчера на Github (http://github.com/jonathangeiger/kohana-jelly) появилась версия с документацией на русском.
Спасибо Сергею Гладковскому! (http://github.com/smgladkovskiy)
2 Александр Купреев 23-04-2010 22:05
да, Jelly мне кажется достаточно удобным инструментом, хотя тут не имею большого опыта. А на русском языке вообще приятно читать
3 biakaveron 11-05-2010 14:32
1.
Добавьте проверку на наличие этих ключей. Arr::get() я уже на автопилоте подставляю в любом месте, где работаю с массивами
2. А зачем пункт "в" в реализации автологина? Для этого обычно используется метод Auth::instance()->auto_login(), который пробует залогиниться на основании кук (вернет TRUE, если получилось). Пихаем его в before(), если не прокатило, то уже тогда предлагаем залогиниться.
4 Александр Купреев 11-05-2010 20:33
пункт в) нужен из-за того, что я изначально отказался от менеджмента доступа к страницам в before(), решив разбираться в каждом методе отдельно
а так конечно -- вы абсолютно правы
5 Anree 13-05-2010 16:11
Александр спасибо Вам за столь интересные статьи.
Я немного поправил код в вашем примере. Надеюсь в лучшую сторону )
1. Контроллер action_users(), ветка 'edit'
2.Форма views/admin/edit_user
Т.е. я в форме убрал лишний цикл и изменил поиск ID в массиве ролей пользователей.
6 Александр Купреев 17-05-2010 15:02
Anree, спасибо за отзыв и простите, что поздно отвечаю -- провайдер подорвал доверие :(
Спасибо за правки, самое то!