Появились у меня недавно некоторые наметки относительно проверки данных при передаче их в базу данных, да и вообще - Zend Db Table не помешало бы немного подлатать…
За модель в Zend Framework отвечает Zend_Db, а точнее - Zend_Db_Table. Т. е. мы создаем классы, которые соответствуют нашим таблицам в базе данных и работаем с ними. Т. к. ORM полноценной в ближайшем будущем в фреймворке не будет, то я попытаюсь за несколько статей сделать хотя бы некое подобие ORM’а.
Данные, которые мы добавляем/изменям в БД, в Zend_Db_Table поступают в следующем виде:
$data = array(
'created_on' => new Zend_Db_Expr('CURDATE()'),
'bug_description' => 'Something wrong',
'bug_status' => 'NEW'
);
т.е. в виде массива, элементы которого представляют собой пары “колонка - значение”.
Для начала я предлагаю сделать достаточно логичную, на мой взгляд, вещь - убрать из этого массива элементы, у которых ключ не соответствует ни одной колонке из таблицы. Названия колонок таблицы хранятся в переменной:
/**
* The table column names derived from Zend_Db_Adapter_Abstract::describeTable().
*
* @var array
*/
protected $_cols;
А если их там нет, то их всегда можно получить, вызвав метод _setupMetadata() класса Zend_Db_Table.
Для начала создадим класс ModelDb, который будет наследовать Zend_Db_Table. Это будет нашим полигоном к улучшению стандартного класса таблицы.
А теперь напишем функцию-метод нашего нового класса, которая будет заниматься проверкой данных на соответствие названиям колонок в таблице:
protected function _check_columns(array $data)
{
if(empty($this->_cols)) {
$this->_setupMetadata();
}
$ret = array();
foreach($data as $key => $value)
{
if(isset($this->_cols[$key])) {
$ret[$key] = $value;
}
}
return $ret;
}
Сначала мы проверяем, есть ли у нас названия колонок и, если их нет, получаем их. Далее мы создаем массив “колонка - значение”, который уже содержит только те пары, ключи которых действительно являются колонками из таблицы и возвращаем их.
Также я сделаю на хотя бы какую-то проверку на переданные данные. Проверять эти данные яя буду с помощью regexp’ов (в будущем это все уберется, но об этом позже). Записывать эти regexp’ы я буду так:
protected $_validate = array(
'название колонки' => 'regexp'
'название колонки' => 'regexp'
'название колонки' => 'regexp'
...
);
А теперь функция-метод для проверки данных:
protected function validate(array $data)
{
if(isset($this->_validate)) {
foreach($data as $key => $value)
{
if(@$this->_validate[$key] && !preg_match($this->_validate[$key], $value)) {
require_once 'Zend/Db/Table/Exception.php';
throw new Zend_Db_Table_Exception("Entered value \"$value\" is not valid");
}
}
}
}
Что мы делаем - проверяем, есть ли у нас вообще массив регулярных выражений (если его нет - все переданные данные нам будут подходить), и если есть - проверяем соответствует ли значение колонки соответствующему регекспу, и если нет - бросаем исключение Zend_Db_Table_Exception.
Функции проверки есть, надо бы их где-нибудь использовать. Финальный листинг файла ModelDb.php:
require_once 'Zend/Db/Table.php';
abstract class ModelDb extends Zend_Db_Table
{
/**
* var array Array of regexps
*/
protected $_validate = array();
/**
* Remove pairs, not matched to table columns, from $data.
*
* @param array $data Column-value pairs.
* @return array Column-value pairs
*/
protected function _check_columns(array $data)
{
if(empty($this->_cols)) {
$this->_setupMetadata();
}
$ret = array();
foreach($data as $key => $value)
{
if(isset($this->_cols[$key])) {
$ret[$key] = $value;
}
}
return $ret;
}
/**
* Validates data
*
* @param array $data Column-value pairs.
* @return void
* @throw Zend_Db_Table_Exception, when data is not valid
*/
protected function validate(array $data)
{
if(isset($this->_validate)) {
foreach($data as $key => $value)
{
if(@$this->_validate[$key] && !preg_match($this->_validate[$key], $value)) {
require_once 'Zend/Db/Table/Exception.php';
throw new Zend_Db_Table_Exception("Entered value \"$value\" is not valid");
}
}
}
}
public function insert(array $data)
{
$data = $this->check_columns($data);
$this->validate($data);
return parent::insert($data);
}
public function update(array $data, $where)
{
$data = $this->check_columns($data);
$this->validate($data);
return parent::update($data, $where);
}
}
Как мы видим - добавилось 2 функции, которые вызывают наши validate() и check_columns() и которые заменяют функции с такими же именами класса Zend_Db_Table.
Вывод из всего - теперь нам нужно наследовать наши классы таблиц не от Zend_Db_Table, а от ModelDb; и для проверки введенных значений нужно в классе таблицы создать переменную $_validate с нужными вам regexp’ами.
На сегодня все, если что-то будет непонятно или вы найдете у меня ошибки - пишите в комменты.
В ближайшии дни - интеграция проверок с Zend_Validate, а также учет типов колонок в таблице.






July 20th, 2008 at 02:10
[...] главу о Zend_Db из документации Zend Framework’а. А также – мой пост про Zend_Db_Table, посвященный его улучшению (правда, я не знаю, [...]