Наверняка многие из вас сталкивались с задачей переноса данных с одного сайта на другой. Например, создали локально представление вьюса - и надо быстро его перенести на рабочий сайт. И вы явно обратили внимание, что в каждом представлении есть вкладка "Экспорт". Благодаря такой возможности вы можете перенести это представление на рабочий сайт буквально за 10 секунд. Фактически происходит следующее: из таблицы выбирается запись с этим представлением, обрабатывается специальным образом и отдаётся пользователю в виде текста. А потом при импорте этот текст декодируется и вставляется как запись в таблицу. Одним из механизмов, позволяющих это реализовывать, является Ctools Exportable - о нём я и расскажу.
Шаг первый. Расширяем схему таблицы.
Для того, чтобы Chaos Tools смог работать с вашей таблицей, надо расширить её описание в hook_schema(), добавив параметр export:
/**
* Implements hook_schema().
*/
function mymodule_schema() {
$schema['mymodule_table'] = array(
'export' => array(
// Первичный ключ таблицы.
'key' => 'oid',
// Идентификатор. Можно указать любое значение.
'identifier' => 'myobj',
// Название своего хука. О нём чуть позже. Но на экспорт он не влияет.
'default hook' => 'default_mymodule_myobj',
// Если не выключить эту опцию, то ctools будет подсовывать в код экспорта
// возможность выключить вставленную запись при её импорте.
'can disable' => FALSE,
// Информация об API вашего модуля.
'api' => array(
// Название модуля.
'owner' => 'mymodule',
// Название файла, подключаемого для API.
'api' => 'default_mymodule_myobjs',
// Минимальная и текущая версия API.
'minimum_version' => 1,
'current_version' => 1,
),
),
// Дальше всё как обычно - описание полей, ключи и т.д.
'fields' => array(
'oid' => array(
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
),
),
'primary key' => array('oid'),
);
return $schema;
}
Обращаю внимание на тот факт, что если данные экспорта были добавлены в модуль уже после его релиза, то не нужно предоставлять дополнительных хуков hook_update_N() для его имплементации в уже созданную таблицу. Данные из массива 'export' будут взяты в оборот после обычного сброса кэша на сайте.
Шаг второй. Реализация экспорта.
Теперь нам надо создать страницу для экспорта записи. Добавляем страницу в хуке меню:
/** * Implements hook_menu(). */ function mymodule_menu() { $items['admin/structure/mymodule/export/%'] = array( 'title' => 'Mymodule object export', 'page callback' => 'drupal_get_form', 'page arguments' => array('mymodule_export_form', 4), // Вообще здесь должен стоять нормальная проверка доступа, // но я поставил TRUE для простоты. 'access callback' => TRUE, ); return $items; }
Вместо %, как можно догадаться, в пути будет находиться ID вашей записи в таблице.
Теперь реализация формы экспорта:
function mymodule_export_form($form, $form_state, $id) {
// Подключаем файл с функциями экспорта.
ctools_include('export');
// Выгружаем объект из базы.
$objects = ctools_export_load_object('mymodule_table', 'all', array($id));
// Убеждаемся, что объект был выгружен.
if (empty($objects[$id])) {
return t('It is not possible to export this object right now. Try again later.');
}
$object = $objects[$id];
// Создаём из выгруженного объекта код для экспорта.
$code = ctools_export_crud_export('mymodule_table', $object);
// Подсчитываем кол-во строк в коде (это уже для удобства).
$lines = substr_count($code, "\n");
// Создаём текстовое поле с выгруженным кодом.
$form['export'] = array(
'#title' => t('Export data'),
'#type' => 'textarea',
'#value' => $code,
'#rows' => $lines,
'#description' => t('Copy the export text and paste it into import area.'),
);
return $form;
}
С экспортом закончили, переходим к импорту.
Шаг третий. Реализация импорта.
Для импорта вам тоже понадобится создать страницу с формой, куда будет вставляться текст с кодом. Поэтому дополняем наш hook_menu() ещё одной страницей:
/** * Implements hook_menu(). */ function mymodule_menu() { $items['admin/structure/mymodule/export/%'] = array( 'title' => 'Mymodule object export', 'page callback' => 'drupal_get_form', 'page arguments' => array('mymodule_export_form', 4), // Вообще здесь должен стоять нормальная проверка доступа, // но я поставил TRUE для простоты. 'access callback' => TRUE, ); $items['admin/structure/mymodule/import'] = array( 'title' => 'Mymodule object import', 'page callback' => 'drupal_get_form', 'page arguments' => array('mymodule_import_form'), // Вообще здесь должен стоять нормальная проверка доступа, // но я поставил TRUE для простоты. 'access callback' => TRUE, ); return $items; }
Теперь создаём форму с импортом:
/** * Форма для импорта объектов. */ function mymodule_import_form($form, $form_state) { // Текстовая область для вставки импортируемого кода. $form['import'] = array( '#type' => 'textarea', '#title' => t('Paste code here to import object'), ); $form['actions'] = array( '#type' => 'action', ); $form['actions']['submit'] = array( '#type' => 'submit', '#value' => t('Import'), ); return $form; } /** * Обработчик импорта объектов. */ function mymodule_import_form_submit($form, &$form_state) { // Забираем полученный код для импорта. $code = $form_state['values']['import']; // Подключаем файл с функциями экспорта/импорта. ctools_include('export'); // Создаем из полученного кода объект с нашей записью. $object = ctools_export_crud_import('mymodule_table', $code); // Убираем ключ из объекта, чтобы была создана новая запись в таблице. unset($object->oid); // Сохраняем объект в базе. $result = drupal_write_record($object); // Выводим сообщение в зависимости от результата записи. if ($result) { drupal_set_message('Запись была успешно импортирована'); } else { drupal_set_message('При импорте возникла ошибка и запись не была импортирована', 'error'); } } Ну вот и вся хитрость. Теперь ваши модули станут удобнее в миграции :)