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:Работа с временными таблицами

From In-Portal Developers Guide

Jump to: navigation, search
База данных База данных
Статьи в этой категории

Временные таблицы это таблицы, создающиеся на время редактирования записей в базе данных. Они предназначены для хранения их данных до момента сохранения или отмены изменений. Временные таблицы создаются при открытии формы редактирования, затем в них копируются данные из оригинальных таблиц. После окончания редактирования (в случае с сохранением изменений) данные копируются обратно в оригинальные таблицы, затем временные таблицы уничтожаются. При отмене редактирования данные не копируются, но временные таблицы также уничтожаются.

Временные таблицы, в первую очередь, были придуманы для редактирования сложных записей. Главное преимущество - возможность отменить все сделанные изменения при редактировании в случаях, когда форма редактирования разбита на несколько последовательно сохраняющихся форм (например, вкладок или форм редактирования подчинённых записей).

Подробнее о связи главных и подчинённых записей можно прочитать в статье Работа с подчинёнными префиксами.

Image:Tipbox Icon.gif
  • При работе с временными таблицами следует принимать во внимание тот факт, что при одновременном редактировании одной записи несколькими людьми в оригинальной таблице останется отредактированный вариант того, кто сохраняет сущность последним.
  • Во временные таблицы также рекурсивно загружаются данные всех подчинённых записей.

Contents

Использование временных таблиц

Для редактирования большинства записей, за редкими исключениями, следует использовать временные таблицы. Также их следует использовать только в административной консоли, т.к. на пользовательской части сайта временные таблицы не применяются. Не следует также использовать временные таблицы в некоторых частных случаях, например, для записи в различные журналы изменений (logs). Каждый подобный случай следует рассматривать отдельно.

Чтобы начать редактирование сущности во временной таблице, следует пользоваться ниже приведённым JavaScript кодом.

std_edit_item('phone', 'custom/phones/phone_edit');

Эта функция в результате передаст в запросе к серверу событие OnEdit. Сама функция "std_edit_item" является стандартной JavaScript функцией платформы и объявляется в файле "core/admin_templates/js/script.js". Ей передаются в качестве параметров префикс и шаблон с формой редактирования.

Для окончания редактирования во временных таблицах и сохранения записи следует вызвать событие OnSave:

submit_event('phone', '<inp2:phone_SaveEvent />');

Тэг SaveEvent вернёт "OnSave" в случае, если item phone является главной и "OnCreate" или "OnUpdate", когда запись является подчинённой.

Для окончания редактирования во временных таблицах не сохраняя произведённые изменения следует вызвать событие OnCancelEdit, которое просто сотрёт использованные в процессе редактирования таблицы. Обычно это делается при помощи вызова ниже приведённого JavaScript кода.

cancel_edit('phone', 'OnCancelEdit', '<inp2:phone_SaveEvent/>', '<inp2:m_Phrase label="la_FormCancelConfirmation" escape="1"/>');

ID записей во временных таблицах

При работе с временными таблицами следует помнить o принципах присвоения ID записям, которые в них хранятся. Они немного отличаются от аналогичных принципов для записей, хранящихся в оригинальных таблицах и заключаются в следующем:

  • те записи, которые существовали на момент начала редактирования, во временных таблицах получают те же ID, что и в оригинальных (т.е. уже существующие записи копируются во временные таблицы без изменений);
  • запись главной сущности при создании во временной таблице (главная сущность во временной таблице в таком случае может быть только одна) получает ID равное нулю ("0");
  • записи подчинённых сущностей при создании во временных таблицах получают отрицательные ID, начиная от "-1".

Следует иметь в виду, что при создании подчинённых сущностей в нестандартной функциональности сразу после вызова метода kDBItem::Create следует вызывать метод kDBItem::setTempID, иначе запись не получит правильный ID и механизм не будет работать корректно. Это будет продемонстрировано на следующем примере.

$phone_accessory->Create();
$phone_accessory->setTempID();
Image:Tipbox Icon.gif Также во временных таблицах отсутствует auto increment. Это особо важно при создании подчинённых сущностей - без вызова метода kDBItem::setTempID все они получат одинаковые ID, равные нулю ("0").

После сохранения и копирования в оригинальные таблицы созданные во временных таблицах записи получают новые ID, получающиеся обычно при помощи auto increment'а.

Обработка записей после копирования из временной таблицы в оригинальную

Чтобы обработать данные сразу после копирования в оригинальные таблицы с учётом новых ID, обычно переписываются два события:

  • OnAfterCopyToLive - вызывается после копирования каждой записи. Ему передаются два параметра:
параметр описание
id (int) ID записи в оригинальной таблице
temp_id (int) ID записи во временной таблице.
  • OnSave - переписать и после вызова родительского метода использовать параметр параметр ids, в котором находятся ID записей в оригинальной таблице.

Использование временных таблиц в ItemSQLs и ListSQLs

Иногда в опциях ItemSQLs или ListSQLs, для LEFT JOIN или для вложенного запроса (subselect), требуется использовать название таблицы, в которой запись сейчас редактируется, т.е. временная или оригинальная. Для этого нужно перед названием таблицы поставить "%3$s", например:

'ListSQLs' => Array (
	'' => '	SELECT %1$s.* %2$s
		FROM %1$s
		LEFT JOIN ' . TABLE_PREFIX . '%3$sPhoneAccessories AS phac ON %1$s.PhoneId = phac.PhoneId'
),

Данную функциональность следует использовать только для таблиц, записи в которых состоят в родственных отношениях с данной (т.е. подчинённых записей).

Схема работы класса kTempTablesHandler

Для реализации основных функций по работе с временными таблицы в платформе используется класс "kTempTablesHandler". Данный класс предоставляет ряд методов, для использования в обработчике событий:

  • PrepareEdit - реализует создание временных таблиц и копирование туда данных из оригинальный таблиц для последующего редактирования; в случае создания новой записи ограничивается лишь созданием временных таблиц;
  • SaveEdit - сохраняет данные после редактирования, а именно удаляет данные из оригинальных таблиц, копирует на их место данные из временных таблиц, удаляет временные таблицы;
  • CancelEdit - удаляет временные таблицы;

Подробнее схема работы этих методов изображена на ниже приведённых диаграммах.

Копирование во временные таблицы при редактировании записей
Копирование во временные таблицы при редактировании записей
Создание временных таблиц при создании записи
Создание временных таблиц при создании записи
Копирование в оригинальные таблицы при сохранении записей
Копирование в оригинальные таблицы при сохранении записей
Удаление временных таблиц при отмене редактирования
Удаление временных таблиц при отмене редактирования

Названия временных таблиц

Названия временных таблиц получаются при помощи метода kApplication::GetTempName. Как видно из приведённого ниже кода данного метода, название временной таблицы состоит из следующих частей:

  • значение константы TABLE_PREFIX;
  • текст "ses_";
  • ID пользовательской сессии;
  • ID окна (если есть, является уникальным для каждого всплывающего окна редактирования сущности);
  • текст "_edit_";
  • имя оригинальной таблицы (также со значением константы TABLE_PREFIX).
function GetTempName($table, $wid = '')
{
	if (preg_match('/prefix:(.*)/', $wid, $regs)) {
		$wid = $this->GetTopmostWid($regs[1]);
	}
 
	return TABLE_PREFIX . 'ses_' . $this->GetSID() . ($wid ? '_'.$wid : '') . '_edit_' . $table;
}

Если редактирование происходит во всплывающем окне, то второй параметр, содержащий идентификатор окна (wid - window id) является обязательным. В случае, когда он не известен, то можно вместо него передать строку вида "prefix:<item_prefix>" где после слова "prefix:" указать префикс конфигурационного файла, с которым связана переданная в первом параметре таблица.

Удаление временных таблиц

Временные таблицы в нормальных условиях удаляются в процессе сохранения редактируемых записей, либо отмены редактирования. Также предусмотрен случай закрытия окна крестиком, при котором также вызывается событие OnCancelEdit. Но бывают ситуации, когда временные таблицы невозможно удалить нормальным способом (например, зависание компьютера или браузера, выключение электричества и т.д.). В таком случае временные таблицы будут удалены при завершении сессии.

Дополнительные возможности класса kTempTablesHandler

Класс kTempTablesHandler, кроме функций, относящихся к работе с временными таблицами, также имеет дополнительные методы, которые используют родственные связи между сущностями. В данный класс такие методы попали как раз потому, что у класса уже имеется механизм построения и работы с деревом родственных связей.

Удаление

Стандартный способ реализации функции удаления в проекте - кнопка, на панели инструментов над в списком, вызывающая событие OnMassDelete. Данное событие для удаления записей использует класс kTempTablesHandler, т.к. удаляя главную запись, обычно требуется удалить также и все подчинённые (по цепочке). В событии OnMassDelete вызывается метод kTempTablesHandler::DeleteItems, которому передаются префикс, special и список ID записей, выбранных для удаления в списке.

Полный список параметров метода kTempTablesHandler::DeleteItems следующий:

параметр описание
$prefix (string) Префикс сущности, которую нужно удалить.
$special (string) special сущности, которую нужно удалить.
$ids (array) Список ID записей для удаления.
$master (array) Массив параметров сущности, элемент дерева родственных связей. Передаётся внутри самого метода kTempTablesHandler::DeleteItems для рекурсивного удаления подчинённых сущностей.
$foreign_key (int) Ключ для связи подчинённых сущностей с главной; передаётся внутри самого метода kTempTablesHandler::DeleteItems для рекурсивного удаления подчинённых сущностей.

Задать необходимость удаления подчинённых сущностей при удалении главной можно с помощью опции AutoDelete в конфигурационном файле подчинённого префикса, например:

'AutoDelete' => true,

Клонирование (копирование)

Стандартный способ реализации функции клонирования в проекте - кнопка, на панели инструментов над в списком, вызывающая событие OnMassClone. Данное событие для клонирования сущностей использует класс kTempTablesHandler, так как клонируя главную сущность, обычно требуется клонировать также и подчинённые (по цепочке). В событии OnMassClone вызывается метод kTempTablesHandler::CloneItems, которому передаются префикс, special и список ID сущностей, выбранных для клонирования в списке.

Полный список параметров метода kTempTablesHandler::CloneItems следующий:

параметр описание
$prefix (string) Префикс сущности, которую нужно клонировать.
$special (string) special сущности, которую нужно клонировать.
$ids (array) Список ID сущностей для клонирования.
$master (array) Массив параметров сущности, элемент дерева родственных связей; передаётся внутри самого метода kTempTablesHandler::CloneItems для рекурсивного клонирования подчинённых сущностей.
$foreign_key (int) Ключ для связи подчинённых сущностей с главной; передаётся внутри самого метода kTempTablesHandler::CloneItems для рекурсивного клонирования подчинённых сущностей.
$parent_prefix (string) Префикс главной сущности по отношению к текущей; передаётся внутри самого метода kTempTablesHandler::CloneItems для рекурсивного клонирования подчинённых сущностей.
$skip_filenames (bool) Задаёт необходимость преобразования имён сущностей. Поле, содержащие именя сущности определяется в опции TitleField конфигурационного файла. Например, при значении параметра true имя "Nokia N73" преобразуется в "Copy of Nokia N73", а "Copy of Nokia N73" - в "Copy 2 of Nokia N73" и т.д.

Задать необходимость клонирования подчинённых сущностей при клонировании главной можно с помощью опции AutoClone в конфигурационном файле, например:

'AutoClone' => true,

См. также