====== Шаг4.1 Управление списком пользователей ====== ===== Создание класса User ===== Реализация пользователей должна отвечать следующим требованиям: * В системе не должно быть пользователей с одинаковыми логинами и email-адресами. * Пароли пользователей не должны храниться в базе данных в открытом виде. ==== Правило валидации UserUniqueFieldRule ==== При помощи класса **UserUniqueFieldRule** мы будем проверять наличие одного уникального пользователя со значением какого-либо поля. Это правило валидации потом будет использоваться в классе **User**. Файл shop/src/validation/UserUniqueFieldRule.class.php: current_user = $current_user; parent :: __construct($field); } function check($value) { $user = new User(); $records = $user->findAllRecords(new lmbSQLFieldCriteria($this->field_name, $value)); if($records->count() && ($this->current_user->isNew() || $this->_sameFieldUserRecordExists($records))) $this->error('User with the same value of {Field} already exists'); } function _sameFieldUserRecordExists($records) { foreach($records as $record) { if($record->get('id') != $this->current_user->getId()) return true; } return false; } } ?> Класс UserUniqueFieldRule получает в конструкторе название поля, которое должно быть уникальным, и ссылку на текущего пользователя. Текущий пользователь понадобится нам при редактировании. Класс **lmbSingleFieldRule** является базовым для правил валидации одного поля. Файл класса можно найти по пути limb/validation/src/rule/lmbSingleFieldRule.class.php Дочерние классы должны перекрывать метод **check($value)**, где $value - значение поля, которое необходимо проверить. Следует отметить, что check($value) не вызывается, если $value не содержит значимого значения. Поэтому совместно с этим правилом (его дочерними) рекомендуется использовать также правило **lmbRequiredFieldRule**. Об этом ты также упомянем чуть ниже при описании кода класса User. При помощи [[limb3:ru:packages:active_record:find|find-метода класса lmbActiveRecord]] делается запрос к базе данных. В качестве второго параметра вместо $params можно передавать объект критерии, которая будет накладываться на выборку. Критерия - это объектная форма условия. В нашем случае использовался класс **lmbSQLFieldCriteria**, который принимает в конструкторе название поля и значение (по-умолчанию для этой пары формируется условие равенства). Использование критериев позволяет не думать о экранировании данных в SQL-запросах. Вы можете подробнее ознакомиться с классами [[limb3:ru:packages:dbal:criteria|Criteria]], однако это необязательно для понимания данного примера. Метод lmbSingleFieldRule :: **error($error_string, $values = array())** добавляет ошибку в список ошибок валидации. Выражения вида {Field} будут заменены в процессе работы на реальные имена полей формы, с которой производится создание/редактирование пользователя. ==== Код класса User ==== Теперь можно написать код класса User. Файл shop/src/model/User.class.php: 'ASC'); protected $password; protected function _createValidator() { $validator = new lmbValidator(); $validator->addRequiredRule('login'); $validator->addRequiredRule('email'); $validator->addRequiredRule('name'); lmb_require('src/validation/UserUniqueFieldRule.class.php'); $validator->addRule(new UserUniqueFieldRule('login', $this)); $validator->addRule(new UserUniqueFieldRule('email', $this)); lmb_require('limb/validation/src/rule/lmbEmailRule.class.php'); $validator->addRule(new lmbEmailRule('email')); return $validator; } protected function _onBeforeSave() { $this->_generatePassword(); } protected function _generatePassword() { if($this->password) $this->setHashedPassword(self :: cryptPassword($this->password)); } static function cryptPassword($password) { return md5($password); } } ?> Создаваемый в методе _createValidator() валидатор проверяет, что поля email и login должны быть заполнены и иметь уникальные значения. Последнее обеспечивается за счет использования правила UserUniqueFieldRule. Правило lmbEmailRule удостоверяется, что введенное в поле значение является электронным адресом. Обратите внимание на метод **_onBeforeSave()**. Это так называемый метод расширения класса lmbActiveRecord, который дочерние классы могут использовать чтобы выполнять необходимые действия, например, перед сохранением новой записи, перед обновлением существующей, после сохранения и т.д. Список методов расширения класса lmbActiveRecord есть в разделе [[limb3:ru:packages:active_record:enhancement|"Расширение поведения базового класса lmbActiveRecord"]]. В нашем случае мы использовали этот метод, чтобы шифровать поле **password** и формировать значение поля **hashed_password**. Таким образом мы будем хранить только хешированный пароль, а обновление хешированного пароля будет происходить только, если в поле password есть новое значение. ===== Создание шаблонов и контроллера для управления пользователями ===== Надеемся, что это часть не составит для Вас никакого труда. Новые для вас моменты должны быть в реализации действий по созданию нового пользователя и смене пароля в контроллере AdminUserController. Там мы будем использовать дополнительный валидатор для проверки полей с паролями. Получится, что в итоге данные с одной формы будут валидироваться дважды - один раз в контроллере, другой раз в ActiveRecord-е. ==== Шаблоны ==== Файл shop/template/admin_user/create.html:
Файл shop/template/admin_user/edit.html:
Файл shop/template/admin_user/form_fields.html:
Файл shop/templates/admin_user/display.html: Create user
Name Login E-mail Actions
{$name} {$login} {$email} Change password Edit Delete
==== Контроллер AdminUserController ==== При реализации контроллера AdminUserController мы также создадим общий метод _performCreateOrEdit(), как и в AdminProductController, который будет отвечать за создание и редактирование учетных записей пользователей. Дополнительно вы введем проверку при создании пользователя, что значения полей password и repeat_password должны совпадать. Так мы покажем как можно валидировать данные, пришедшие с форм, прямо в контроллере. Файл shop/src/controller/AdminUserController.class.php: _performCreateOrEdit(); } function doEdit() { $this->_performCreateOrEdit(); } protected function _performCreateOrEdit() { if(!$id = $this->request->getInteger('id')) $id = null; $item = new User($id); $this->useForm('user_form'); $this->setFormDatasource($item); if($this->request->hasPost()) { $item->import($this->request); if($this->request->get('create')) $this->_validatePasswordField(); if($item->trySave($this->error_list)) $this->redirect(); } } function doDelete() { $item = new User($this->request->getInteger('id')); $item->destroy(); $this->redirect(); } function _validatePasswordField() { $this->validator->addRequiredRule('password'); $this->validator->addRequiredRule('repeat_password'); lmb_require('limb/validation/src/rule/lmbMatchRule.class.php'); $this->validator->addRule(new lmbMatchRule('password', 'repeat_password')); $this->validator->validate($this->request); } } ?> Рассмотрим метод **_validatePasswordField()**. Класс lmbController по-умолчанию содержит объект валидатора **$validator**, которому передали список ошибок $error_list. В методе мы добавили в этот валидатор три правила: * lmbRequiredRule для поля repeat_password, * lmbRequiredRule для поля password и * lmbMatchRule для полей password и repeat_password. lmbMatchRule удостоверяется, что значения двух полей совпадают. Метод lmbValidator :: **validate($datasource)** проверяет переданный контейнер данных $datasource при помощи ранее добавленных в него правил. В нашем случае мы отдали на проверку объект Запроса $request. Теперь можете попробовать создать уникальных пользователей, пользователей с дублирующимися логинами и т.д. ==== Смена пароля пользователей ==== Добавим также действие по смене пароля, скажем **change_password**. Текущий зарегистированный администратор сможет легко менять пароли пользователей. Для этого нам необходимо будет добавить новый метод **doChangePassword()** в **AdminUserController** и новый шаблон **change_password.html**: Файл shop/template/admin_user/change_password.html:
Изменения в файле shop/src/controller/AdminUserController.html: class AdminUserController extends lmbController { [...] function doChangePassword() { if(!$this->request->hasPost()) return; $this->useForm('user_form'); $this->setFormDatasource($this->request); $this->_validatePasswordField(); if(!$this->error_list->isValid()) return; $user = new User($this->request->getInteger('id')); $user->setPassword($this->request->get('password')); if($user->trySave($this->error_list)) $this->redirect(); } [...] } Здесь мы также использовали метод _validatePasswordField() для проверки полей для ввода паролей. ===== Далее ===== Мы сделали модуль по управлению пользователей. Мы рекомендуем вам при помощи этой новой функциональности добавить себе пользователя с установленных флагом "Is Admin" и приступить к следующему шагу: [[step4-2|"Шаг4.2 Аутентификация пользователей"]].