In-Portal Developers Guide

This is a wiki-based Developers Guide for In-Portal Open Source CMS. The purpose of this guide is to provide advanced users, web developers and programmers with documentation on how to expand, customize and improve the functionality and the code the In-Portal software. Please consider contributing to our documentation writing effort.

K4:Работа с классом kDBItem

From In-Portal Developers Guide

Jump to: navigation, search
Системные классы Системные классы
Статьи в этой категории
  • Работа с классом kDBItem
  • KHTTPQuery

Класс kDBItem - один из базовых классов. Он предоставляет методы для работы с данными, относящимися к одной записи. Для связи объектов класса kDBItem с прочими частями системы широко используются события. События происходящие во время выполнения методов класса kDBItem можно перехватывать и выполнять необходимые действия. И наоборот - в системе имеются события, при наступлении которых выполняются методы класса kDBItem.

Contents

Загрузка из базы данных

Для загрузки из базы данных используется метод Load. Метод возвращает значение true в случае успешной загрузки данных и false в прочих случаях. Если требуется проверить факт успешной загрузки из базы данных у отдельно взятого объекта, то можно использовать метод isLoaded, который возвращает статус последней загрузки объекта. Условия загрузки данных задаются параметрами метода. Они могут быть простыми и сложными.

Простое условие загрузки получается если первым параметром передаётся значение одного из полей записи. Обычно это Integer значение первичного ключа и тогда второй параметр не нужен. Если первым параметром передают значение другого поля, то вторым параметром должно быть название соответствующего поля.

// получаем ссылку на объект. Третий параметр предотвращает автоматическую загрузку данных в объект
$user =& $this->Application->recallObject('u', null, Array('skip_autoload' => true));
/* @var $user kDBItem */
 
// загружаем данные объекта с ID = 23
$user->Load(23);
 
// Тут могут быть всякие действия с объектом
 
// Загружаем в объект данные пользователя по его адресу электронной почты
$user->Load('erik@intechnic.com', 'Email');

Сложное условие загрузки получается если первым параметром передать массив, содержащий в качестве ключей имена полей а в качестве значений - значения, которые должны быть в соответствующих полях у загруженной записи.

$load_keys = Array(
	'FirstName' => 'Erik',
	'LastName' => 'Snarski'
);
 
$user->Load($load_keys);

В итоге для загрузки данных будет использоваться SQL-запрос с условием следующего вида:

WHERE FirstName = 'Erik' AND LastName = 'Snarski'

Изменение данных

Для изменения данных одного поля используются методы SetField и SetDBField. SetDBField записывает в поле значение параметра $value в точности таким как оно передано. SetField перед тем как записать значение, проверяет не назначен ли для поля форматер, и если назначен, то трансформирует значение поля методом Parse форматера.

// например в случае с форматированием даты
$user->SetField('dob', '12/22/1971');
// результат операции будет эквивалентен
$user->SetDBField('dob', 62197200);

Часто бывает удобно поменять данные сразу в нескольких полях. Например, переписать значения полей, которые пришли в результате submit-а формы. Для этого имеются функции SetFieldsFromHash и SetDBFieldsFromHash. Они принимают в качестве параметра массив, содержащий имена полей и значения для них. SetFieldsFromHash, как вышеупомянутый SetField, вызывает метод Parse форматера для трансформации значений.

$field_values = Array(
	'Email' => 'erik@intechnic.com',
	'FirstName' => 'Erik',
	'LastName' => 'Snarski',
	'dob' => '12/22/1971'
);
// обычно подобный массив получают из запроса конструкцией вида
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
list ($id, $field_values) = each($items_info);
 
// и, наконец - запись данных в объект
$user->SetFieldsFromHash($field_values);

Иногда, например при импорте данных, приходится один и тот же объект класса kDBItem использовать многократно с разными наборами данных. В таких случаях может оказаться полезным метод Clear, выставляющий всем полям значения по умолчанию и таким образом гарантирующий, что в каждом наборе будут только его собственные данные.

Определение изменившихся полей

Часто бывает полезно при изменении данных объекта также проверить какие именно поля менялись а какие - нет. Например, если какие-то действия есть смысл производить только при изменениях в определённых полях. Получить значение поля, которое было до изменения данных, сразу после загрузки данных из базы можно с помощью метода GetOriginalField.

Проверка

Для проверки данных объекта применяется метод Validate. Если в ходе выполнения метода обнаруживается несоответствие данных предъявляемым к ним требованиям, то в свойство FieldErrors объекта, представляющее собой массив с именами полей в качестве ключей верхнего уровня, дописываются элементы второго уровня с ключами 'pseudo'. Это коды ошибок, коротко описывающие сущность проблемы. Проверить есть ли в объекте такие коды можно методом HasErrors.

Увидеть эти коды можно в отладчик, если открыть его после неудачной попытки сохранения записи.

[Name] = Array
        (
            [pseudo] = required
        )

Иногда бывает необходимо не только считывать информацию об ошибках в полях, но и записывать её. Например, при написании функций проверки данных, специфических для конкретной задачи. Тогда, для обозначения ошибок в поле следует использовать предоставляемый классом kDBItem метод SetError.

Например, при редактировании данных в форме можно выбрать из списка категорию, к которой отностится объект. Однако, перед сохранением в базу данных хорошо бы убедиться что категория с таким номером действительно существует:

/**
 *
 * @param kEvent $event
 */
function OnBeforeItemUpdate(&$event)
{
	$object =& $event->getObject();
	/* @var $object kDBItem */
 
	$category_id = $object->getDBField('CategoryId');
	if (!$category_id) {
		// значение не задано - проверка не нужна
		return;
	}
 
	if ($category_id == $object->GetOriginalField('CategoryId')) {
		// значение не изменялось - проверка не нужна
		return;
	}
 
	$sql = 'SELECT COUNT(*)
		FROM ' . $this->Application->getUnitOption('c', 'TableName') . '
		WHERE ' . $this->Application->getUnitOption('c', 'IDField') . ' = ' . $this->Conn->qstr($category_id);
	if (!$this->Conn->GetOne($sql)) {
		$object->SetError('CategoryId', 'invalid_category', 'la_error_InvalidCategory');
	}
}

Сохранение в базу данных

Для сохранения в базу данных используются методы Create и Update. Метод Create предназначен для создания новой записи. Метод Update - для изменения существующей записи. Оба эти метода по умолчанию, перед тем как записывать данные в базу, делают проверку методом Validate, и производят запись только в случае если проверка пройдена успешно. В приведённом ниже примере делается импорт данных, правда, если данные создаваемого пользователя не пройдут проверку, то запись просто не будет создана.

// считываем данные из внешнего источника данных в массив
$sql = 'SELECT username, password, email
	FROM user';
$users = $application->Conn->Query($sql);
 
// создаём объект класса kDBItem
$user =& $application->recallObject('u.-item', null, Array('skip-autoload' => true));
/* @var $user kDBItem*/
 
foreach ($users AS $user_data) {
	// выставляем значения по умолчанию вызовом метода Clear
	$user->Clear();
 
	// выставляем значения полей импортируемой записи
	$user->SetDBField('Login', $user_data['username']);
	$user->SetDBField('Email', $user_data['email']);
	$user->SetDBField('Password', $user_data['password']);
	$user->SetDBField('VerifyPassword', $user_data['password']);
 
	// вызываем метод Create для создания записи в нашей системе
	$user->Create();
}

Использование событий

Четыре основных метода класса kDBItem, способные непосредственно обращаться к базе данных - это методы:

  • Create;
  • Load;
  • Update;
  • Delete.

Каждый из них в определённых ситуациях вызывает события, которые можно использовать для связи объекта класса kDBItem с остальными частями системы. Все эти четыре метода могут в ходе своего выполнения вызывать события OnBeforeItem**** и OnAfterItem****, где **** - имя метода. Событие OnBeforeItem**** вызывается до обращения к базе данных. Событие OnAfterItem**** вызывается только после успешного обращения к базе данных.

Методы Create и Update могут вызывать ещё и событие OnAfterItemValidate. Это происходит в случае, если производилась проверка данных объекта и эта проверка прошла успешно. Событие OnAfterItemValidate вызывается до того как произойдёт обращение к базе данных. Ниже приведён пример того, как можно использовать событие OnAfterItemDelete для выполнения дополнительных действий после успешного удаления записи.

function OnAfterItemDelete(&$event)
{
	$object =& $event->getObject();
	/* @var $object kDBItem */
 
	// несмотря на то что запись в базе данных уже удалена, в памяти хранятся все её данные и
	// в зависимости от значения полей удалённой записи можно выполнять разные действия
	$topic_id = $object->GetDBField('TopicId');
	if (!$topic_id) {
		// deleting non-existing post
		return ;
	}
 
	$post_helper =& $this->Application->recallObject('PostHelper');
	/* @var $post_helper PostHelper */
 
	// update posts count in topic
	$post_helper->updatePostCount($topic_id, -1);
}

Основные события, использующие этот класс

Основные события, которые используют класс kDBItem находятся в классе kDBEventHandler.

Основные События Аналоги, используемые при работе с временными таблицами Используемые методы kDBItem
OnNew OnPreCreate setID(0)
OnCreate OnPreSaveCreated SetFieldsFromHash, Create, IsTempTable, setTempID, setID
OnUpdate OnPreSave Load, SetFieldsFromHash, Update, Load

Эти события как правило инициируются непосредственно с web-страницы, то есть, их имена передаются в запросе к серверу.

Событие OnNew происходит при открытии формы ввода данных для создания новой записи.

  • OnCreate - при отсылке данных на сервер для создания новой записи.
  • OnUpdate - при отсылке данных на сервер для модификации существующей записи.
function OnUpdate(&$event)
{
	// Получаем ссылку на объект класса kDBItem.
	$object =& $event->getObject( Array('skip_autoload' => true) );
 
	// Получаем данные из запроса.
	$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
	if ($items_info) {
		foreach ($items_info as $id => $field_values) {
			// Загружаем данные из базы по идентификатору записи
			$object->Load($id);
 
			// Вставляем данные из запроса в объект.
			$object->SetFieldsFromHash($field_values);
 
			$this->customProcessing($event, 'before');
 
			// Вызываем метод класса kDBItem.
			if ( $object->Update($id) ) {
				$this->customProcessing($event, 'after');
				$event->status=erSUCCESS;
			}
			else {
				$event->status=erFAIL;
				$event->redirect=false;
				break;
			}
		}
	}
	$event->setRedirectParam('opener', 'u');
}

См. также