Прежде, чем писать HTML код для формы, нам нужно определить, какие данные мы будем получать от пользователей и каким правилам они должны соответствовать. Для фиксации этой информации можно использовать класс модели данных. Модель данных, как говорится в разделе Модель, это центральное место для хранения и проверки данных, вводимых пользователем.
В зависимости от того, каким образом используются данные ввода, мы можем создать два типа модели данных. Если мы получаем данные, обрабатываем их, а затем удаляем, то используем модель формы; если же получаем данные и сохраняем их в базу данных, используем Active Record. Оба типа моделей данных используют один и тот же базовый класс CModel, который определяет общий интерфейс, используемый формой.
Примечание: В примерах этого раздела используются модели формы. Тем не менее, всё может быть в равной степени применено и к моделям Active Record.
Ниже мы создадим класс модели LoginForm, который будет использоваться для
получения данных, вводимых пользователем на странице авторизации. Поскольку
эти данные используются исключительно в целях аутентификации пользователя и
сохранять их не требуется, то создадим модель LoginForm как модель формы.
class LoginForm extends CFormModel { public $username; public $password; public $rememberMe=false; }
Мы объявили в LoginForm три атрибута: $username, $password и $rememberMe.
Они используются для хранения имени пользователя, пароля, а также значения опции сохранения
имени пользователя. Так как $rememberMe по умолчанию имеет значение false, то изначально
в форме авторизации галочка этой опции будет снята.
Информация: Термин «атрибут» используется, чтобы отделить свойства, определяемые этими переменными-членами класса, от прочих свойств. Здесь атрибут — это свойство, которое используется в основном для хранения данных, вводимых пользователем, или данных, получаемых из базы данных.
В момент, когда пользователь отправляет данные формы, а модель их получает,
нам необходимо удостовериться, что эти данные корректны, прежде, чем мы будем их использовать.
Это осуществляется посредством проверки данных в соответствии с набором правил.
Правила проверки задаются в методе rules(), который возвращает массив сконфигурированных правил.
class LoginForm extends CFormModel { public $username; public $password; public $rememberMe=false; private $_identity; public function rules() { return array( array('username, password', 'required'), array('rememberMe', 'boolean'), array('password', 'authenticate'), ); } public function authenticate($attribute,$params) { $this->_identity=new UserIdentity($this->username,$this->password); if(!$this->_identity->authenticate()) $this->addError('password','Неправильное имя пользователя или пароль.'); } }
В коде, представленном выше, username и password — обязательные для заполнения поля,
поле password должно быть проверено также на соответствие указанному имени пользователя.
Поле rememberMe может принимать значения true или false.
Каждое правило, возвращаемое rules(), должно быть задано в следующем формате:
array('AttributeList', 'Validator', 'on'=>'ScenarioList', …дополнительные параметры)
где AttributeList — строка с именами атрибутов, отделенных запятыми, которые должны
быть проверены в соответствии с правилами; Validator указывает на тип используемой проверки;
параметр on — необязательный параметр, устанавливающий список сценариев, где должно
использоваться правило; а также прочие параметры — пары имя-значение, которые используются для
инициализации значений свойств соответствующего валидатора.
Есть три способа указать Validator в правиле проверки. Во-первых, Validator может быть именем
метода в классе модели данных, аналогично authenticate в примере выше. Метод проверки
оформляется следующим образом:
/** * @param string $attribute имя поля, которое будем валидировать * @param array $params дополнительные параметры для правила валидации */ public function ValidatorName($attribute,$params) { … }
Второй способ — указать Validator в качестве имени класса. В этом случае для проверки данных в момент применения правила создается
экземпляр класса проверки. Дополнительные параметры в правиле используются для
инициализации значений атрибутов экземпляра. Класс проверки должен быть производным классом от CValidator.
Третий вариант — предопределить псевдоним класса валидатора. В примере выше, имя
required — это псевдоним класса CRequiredValidator, который проверяет, чтобы
проверяемое значение атрибута не было пустым. Ниже приведен полный список предопределенных псевдонимов валидаторов,
включенных в состав Yii:
boolean: псевдоним класса CBooleanValidator, который проверяет, чтобы
атрибут имел значение либо CBooleanValidator::trueValue либо CBooleanValidator::falseValue;
captcha: псевдоним класса CCaptchaValidator, который проверяет, чтобы
значение атрибута было равно коду верификации на капче;
compare: псевдоним класса CCompareValidator, который проверяет, чтобы
значение атрибута совпадало со значением другого атрибута или константой;
email: псевдоним класса CEmailValidator, который отвечает за проверку корректности email адреса;
date: псевдоним класса CDateValidator, проверяющего, является ли атрибут
корректной датой, временем или и тем и другим.
default: псевдоним класса CDefaultValueValidator, который присваивает значение
по умолчанию выбранным атрибутам;
exist: псевдоним класса CExistValidator, который проверяет наличие значения атрибута в указанном столбце таблицы;
file: псевдоним класса CFileValidator, отвечающего за проверку атрибута на
наличие в нем имени загруженного файла;
filter: псевдоним класса CFilterValidator, преобразовывающего
атрибут с использованием фильтра;
in: псевдоним класса CRangeValidator, который проверяет, содержатся ли данные в
заданном наборе значений;
length: псевдоним класса CStringValidator, который проверяет соответствует ли
длина данных заданному интервалу;
match: псевдоним класса CRegularExpressionValidator, проверяющего данные
на соответствие регулярному выражению;
numerical: псевдоним класса CNumberValidator, проверяющего, являются ли
данные корректным числовым значением;
required: псевдоним класса CRequiredValidator, который проверяет, чтобы
значение атрибута не было пустым;
type: псевдоним класса CTypeValidator, проверяющего соответствие атрибута
заданному типу данных;
unique: псевдоним класса CUniqueValidator, который проверяет, являются ли
данные уникальными в пределах поля базы данных;
url: псевдоним класса CUrlValidator, отвечающего за проверку корректности URL.
Ниже представлены несколько примеров использования предопределенных валидаторов:
// имя пользователя — обязательное поле формы array('username', 'required'), // длина имени пользователя должна быть от 3 до 12 символов включительно array('username', 'length', 'min'=>3, 'max'=>12), // в сценарии регистрации значения полей «password» и «password2» должны быть равны array('password', 'compare', 'compareAttribute'=>'password2', 'on'=>'register'), // в сценарии авторизации поле `password` должно быть проверено на соответствие указанному имени пользователя array('password', 'authenticate', 'on'=>'login'),
После того, как создан экземпляр модели данных, нам часто требуется заполнить его данными, которые ввел пользователь. Это можно проделать легко и непринужденно, используя массовое присваивание:
$model=new LoginForm; if(isset($_POST['LoginForm'])) $model->attributes=$_POST['LoginForm'];
Последнее выражение в примере как раз и является массовым присваиванием, где значение каждой переменной в
$_POST['LoginForm'] присваивается соответствующему атрибуту модели.
Это эквивалентно следующей операции:
foreach($_POST['LoginForm'] as $name=>$value) { if($name является безопасным атрибутом) $model->$name=$value; }
Очень важно определить, какие атрибуты являются безопасными. Например, если мы сделаем первичный ключ таблицы безопасным, злоумышленник сможет получить шанс его изменить и, таким образом, изменить данные, которые он не должен менять, поскольку не авторизован для этого.
Атрибут считается безопасным, если он появляется в правиле валидации, применяемом в данном сценарии. Например,
array('username, password', 'required', 'on'=>'login, register'), array('email', 'required', 'on'=>'register'),
В коде выше атрибуты username и password необходимы в сценарии
login, а атрибуты username, password и email — в
сценарии register. В результате, если мы проводим массовое присваивание в
сценарии login, то только атрибуты username и password будут массово
присвоены, т.к. только они входят в правило валидации для сценария login.
С другой стороны, если текущим сценарием является register, то все три атрибута могут
быть массово присвоены.
// сценарий входа $model=new User('login'); if(isset($_POST['User'])) $model->attributes=$_POST['User']; // сценарий регистрации $model=new User('register'); if(isset($_POST['User'])) $model->attributes=$_POST['User'];
Так почему же мы используем именно такую политику для определения, является атрибут безопасным или нет? Если атрибут уже есть в одном или нескольких правилах валидации, зачем беспокоиться о чём-то ещё?
Важно помнить, что правила валидации используются для проверки введенных пользователем данных, а не данных, которые мы генерируем в коде (например, текущее время или автоматически сгенерированный первичный ключ). Поэтому, НЕ ДОБАВЛЯЙТЕ правила валидации для атрибутов, не являющихся введёнными конечным пользователем.
Иногда мы хотим объявить атрибут безопасным даже если в действительности не
имеем правила для него. Пример — атрибут содержания статьи, который может
принимать любые введённые пользователем данные. Для этого мы можем использовать
специальное правило safe:
array('content', 'safe')
Для полноты картины, существует также правило unsafe, используемое для явного
указания небезопасного атрибута:
array('permission', 'unsafe')
Правило unsafe используется редко и является противоположностью описанному
нами ранее определению безопасных атрибутов.
В случае небезопасных входных данных, мы должны присваивать значения соответствующим атрибутам, используя отдельные операции присваивания, как представлено ниже:
$model->permission='admin'; $model->id=1;
Как только модель заполнена пользовательскими данными, вызываем метод CModel::validate(), чтобы запустить процесс проверки. По итогам проверки метод возвращает положительный или отрицательный результат. Для моделей CActiveRecord проверку можно выполнять автоматически в момент вызова метода CActiveRecord::save().
Мы можем задать сценарий через свойство scenario и, с его помощью, задать, какой набор правил использовать для проверки.
Проверка выполняется в зависимости от сценария. Свойство scenario
задаёт сценарий, в котором применяется модель и определяет какой набор правил валидации
использовать. К примеру, в сценарии login, мы хотим проверить только поля модели
пользователя username и password. В сценарии register нам необходимо проверять
большее количество данных: email, address и других. Ниже показано, как провести
проверку для сценария register:
// создаём модель User и задаём её сценарий как `register`. Выражение ниже эквивалентно следующему: // $model=new User; // $model->scenario='register'; $model=new User('register'); // наполняем модель данными $model->attributes=$_POST['User']; // проводим валидацию if($model->validate()) // если данные верны … else …
Сценарий для правил проверки задаётся в свойстве on правила. Если on не определено,
правило используется для всех сценариев. Например,
public function rules() { return array( array('username, password', 'required'), array('password_repeat', 'required', 'on'=>'register'), array('password', 'compare', 'on'=>'register'), ); }
Первое правило будет распространяться на любые сценарии, а два последующих будут применяться
только к сценарию register.
После проверки все возможные ошибки находятся в объекте модели. Мы можем получить их через CModel::getErrors() и CModel::getError(). Первый метод возвращает все ошибки для указанного атрибута модели, второй — только первую ошибку.
Чтобы узнать, возникли ли во время выполнения проверки какие-либо ошибки, можно воспользоваться методом CModel::hasErrors(). И если ошибки действительно есть, то получить их можно с помощью метода CModel::getErrors(). Оба метода могут быть использованы как для всех, так и для конкретного атрибута.
Часто при работе с формами для каждого поля требуется отображать его метку. Она подсказывает пользователю, какие данные ему требуется ввести в поле. Мы, конечно, можем задать метки полей в представлении, но, если указать их непосредственно в модели данных, мы выиграем в удобстве и гибкости.
По умолчанию CModel в качестве меток возвращает названия атрибутов. Изменить их можно, если переопределить метод attributeLabels().
Далее мы увидим, что возможность указания меток в модели данных позволяет быстро создавать сложные формы.
Be the first person to leave a comment
Please login to leave your comment.