20. Универсальная модель базы данных (model)
Класс model является упрощенным вариантом привычного ActiveRecord, реализуя возможность сохранять данные в таблицу БД, а также предварительно проводить фильтрацию и валидацию. Реализацию класса можно найти в файле /core/model.php. Предусмотрены два варианта использования этого класса: динамический, когда перечень полей и их тип задаются непосредственно в коде и статический, когда класс наследуется от базового model и описывает параметры полей таблицы базы данных.
Общий алгоритм работы с классом такой:
-
получить экземпляр класса;
-
передать данные HTML-формы вызвав метод set() или поочерёдно установить все поля сеттерами;
-
вызвать метод validate() для проверки валидности и фильтрации данных;
-
записать данные в базу данных вызвав метод save().
Вот типичный пример динамического использования:
public function actionTestSubmit($data) { //submit-действие контролле
$m=core::model('myTable'); //получение экземпляра класса, myTable — имя таблицы БД
$m->set($data); //передача _POST-данных
$m->myField='some text';
if(!$m->save(array( //сохранить данные, проведя предварительную фильтрацию и валидацию
'id'=>array('primary'),
'name'=>array('string','имя',true,'min'=>2,'max'=>40),
'myField'=>array('string')
))) return false;
core::redirect('myController/myAction','Изменения сохранены');
}
Этот код выполнит запрос INSERT или UPDATE в зависимости от того, задан ли $data['id'] (это поле помечено как первичный ключ).
Вот пример статического класса, содержащего минимум необходимой информации:
class myTable extends model {
protected $fields='id,alias,name'; //список полей, участвующих в SELECT, INSERT и UPDATE, если они не указаны явно
function __construct($db='db') {
parent::__construct('myTable',$db);
}
//Должен возвращать массив, содержащий правила валидации
protected function validateRule() {
'id'=>array('primary'),
'name'=>array('string','имя',true,'min'=>2,'max'=>40),
'myField'=>array('string')
}
//public function beforeInsertUpdate($id,$fields) //выполняется перед INSERT или UPDATE
//public function afterUpdate($id) //выполняется после UPDATE
//public function afterInsert($id) //выполняется после INSERT
}
Использование этого класса:
public function actionTestSubmit($data) { //submit-действие контроллера
core::import('model/myTable');
$m=new myTable();
$m->set($data);
if(!$m->save()) return false;
core::redirect('myController/myAction','Изменения сохранены');
}
Для того, чтобы передать данные полей в модель, необходимо воспользоваться методом set(), принимающем в единственном параметре ассоциативный массив, где ключ - имя, а значение - значение этого поля. Другой путь - установить поля поотдельности при помощи сеттеров. Таким же образом задаётся значение первичного ключа. Если таблица содержит первичный ключ и его значение было передано (не ноль, не null, не false и не пустая строка) в класс model, то при вызове метода save() будет выполнен SQL-запрос «UPDATE». Если же значение первичного ключа не было передано, или оно ложно, то будет выполнен SQL-запрос «INSERT». После выполнения операции INSERT знать значение первичного ключа можно через геттер:
$id=$m->id;
Операция валидации данных проводит также и фильтрацию этих данных в зависимости от указанного типа.
Статический вариант может реализовывать функции beforeInsertUpdate(int id, array fields), afterInsert(int id) и afterUpdate(int id). Эти функции вызываются до или после выполнения SQL-запросов INSERT или UPDATE. Также бывает полезным перегрузить методы load(), validate() и save().
Если функция beforeInsertUpdate возвратит false, то SQL-запрос INSERT или UPDATE выполнен не будет (считается, что валидация не была пройдена). Обычно при этом также требуется установить сообщение об ошибке в глобальную переменную core::$error.
Параметры этих функций следующие: id – значение первичного ключа, fields – список полей, затронутых в SQL-запросе INSERT или UPDATE.
Методы класса
object model::__construct(string namespace[,string db='db']);
тут namespace — имя таблицы базы данных, db — используемая СУБД (может принимать следующие значения: db — указанная в общих настройках (по умолчанию), mysql или sqlite).
null model::set(array data);
Передаёт модели данные полей таблицы, параметр data должен быть ассоциативным массивом, где ключ — имя поля, а значение — содержимое поля.
array model::get();
Возвращает ассоциативный массив, содержащий все поля записи БД.
&array model::load(string where[, string field]);
Загружает данные из базы данных, выбирая запись (одну первую) по указанному в параметре where условию (часть SQL-запроса, после «WHERE». В параметре field указывается перечень (через запятую) полей, которые необходимо выбрать. Если параметр field не указан, то список полей будет взят из атрибута model::$field. Если этот атрибут не был задан, то будут загружены все поля.
Функция возвращает ссылку на ассоциативный массив, поэтому можно менять значения полей «на лету» и записывать данные обратно в базу данных.
&array model::loadById(int id[,string fields]);
Тоже, что model::load(), но загружает данные не по условию, а по уникальному идентификатору.
bool model::validate([array validate]);
Выполняет фильтрацию и валидацию данных. Возвращает true, если проверка прошла успешно. Параметр validate должен быть ассоциативным массивом, содержащим правила валидации (описано далее). В случае статического использования класса этот параметр может быть опущен. Этот метод также устанавливает текст сообщения об ошибке при помощи core::$error.
null model::multiLanguage();
Устанавливает мультиязычный режим: при добавлении новых строк (INSERT) мультиязычные поля копируются на все другие языки (так сказать "значение по умолчанию"). Для мультиязычных таблиц (копии таблиц для каждого языка) выполняется несколько запросов INSERT.
bool model::save([mixed validate],[string fields],[string id]);
Сохраняет данные записи в базе данных. Если в таблице содержится первичный ключ и он не false, то выполняется SQL-запрос «UPDATE», если в таблице нет первичного ключа или он не был задан или он false, то выполняется SQL-запрос «INSERT».
Если параметр validate является массивом, то он воспринимается как правила валидации и перед сохранением будет проведена фильтрация и валидация согласно этим правилам. Если параметр равен true, то валидация будет проведена согласна правилам, заданным в атрибуде model::$validate (только для статического использования). Если параметр validate равен false, то валидация проводиться не будет.
Если задан параметр fields, то в запросе INSERT или UPDATE будут учавствовать только поля, перечисленные в этом параметре. Этот параметр следует использовать только тогда, когда не задан первый параметр (validate), иначе информацию о перечне полей движок сможет взять из правил валидации.
Параметр id может содержать имя первичного ключа — параметр следует использовать в том случае, если не проводится валидация (в противном случае движок найдёт имя первичного ключа в правилах валидации).
bool model::delete([int id],[bool affected]);
Удаляет запись с идентификатором id. Если идентификатор не задан, то будет удалена запись, загруженная ранее. Если параметр affected равен true, то метод возвращает true только в том случае, если запись существовала и действительно была удалена, если её не существовало, то вернёт false. Если включён режим мультиязычности (model::multiLanguage()) и таблица является мультиязычной (отдельные копии таблицы для каждого языка), то будут удалены записи из всех таблиц.
Мультиязычность
Валидация и фильтрация
-
array('primary')
Первичный ключ. Может быть целым числом или строкой. Если этот параметр задан, то будет выполнена SQL-операция UPDATE, если нет, то операция INSERT. Атрибуты 'min' и 'max' задают минимальное и максимальное допустимые значения. -
array('integer',$title=null,$null=true,'min'=>null,'max'=>null)
Целое беззнаковое число. Будет проведена попытка привести к числу при помощи intval(). Если задана пустая строка, то воспринимается как null. Атрибуты 'min' и 'max' задают минимальное и максимальное допустимые значения. -
array('float',$title=null,$null=true,'min'=>null,'max'=>null)
Дробное знаковое число. Будет проведена попытка привести к числу при помощи floatval(). Если задана пустая строка, то воспринимается как null. -
array('boolean',$title=null,$null=true)
Да/нет. Будет проведена попытка привести к числу при помощи boolval(). -
array('date',$title=null,$null=true)
Дата в формате unix timestamp. Если параметр является строкой и содержит не числовые символы, то будет предпринята попытка привести к unix timestamp при помощи strtotime(). Валидация будет неудачной, если в конечном итоге поле не является валидным unix timestamp. -
array('string',$title=null,$null=true,'min'=>null,'max'=>null,'trim'=>false)
Строка, из которой вырезаны все html и другие теги. Атрибуты 'min' и 'max' задают минимальную и максимальную допустимую длину строки. Атрибут 'trim' обрезает начальные и завершающие пробелы. -
array('html',$title=null,$null=true)
Произвольная строка, может содержать любые теги, в том числе <script>. -
array('latin',$title=null,$null=true,'min'=>null,'max'=>null)
Строка, содержащая символы A-Z, 0-9, "-" и "_". Атрибуты 'min' и 'max' задают минимальную и максимальную допустимую длину строки. -
array('email',$title=null,$null=true)
Строка, содержащая адрес электронной почты. Валидация будет неудачной, если параметр не является валидным e-mail. -
array('regular',$title=null,$null=true)
Строка. При валидации проводится сверка с указанным регулярным выражением. -
array('captcha',$title=null)
Поле не сохраняется в базе данных, выполняется только валидация. Верная каптча хранится в $_SESSION['captcha'] (генерируется в файле /captcha.php). -
array('callback',$title=null,$null=true,$function)
Валидация и фильтрация производится пользовательской callback-функцией. В случае неудачной валидации эта функция должна установить текст сообщения об ошибке в переменную core::$error. Третий параметр, $function, задаёт пользовательскую callback-функцию.