Миграция на Друпал. Часть первая: создание нод

Главные вкладки

Аватар пользователя sadmin sadmin 12 ноября 2008 в 9:02

Оригинал: Migrating the Drupal way. Part I: creating a node. Kevin Hankens

Моя позиция в Acquia - помогать миграции и модернизации. Я собираюсь создать блог для обсуждения некоторых общих методов, которые я использую при перемещении клиентов на Drupal.

Переход на Drupal может показаться сложным, если у вас уже существует база данных на сайте. Вместе с тем, наполнение Drupal-сайта может быть проще, чем вы думаете. Мигрируете ли вы из популярных CMS или полностью самописанного приложения, вы можете легко использовать модули Drupal, имитировать текущую структуру данных и перенести ваши данные, используя простой пользовательский PHP скрипт. Я должен отметить, что, хотя существуют разные методы для выполнения этой задачи, некоторые их них являются излюбленными.

Комментарии

Аватар пользователя Химический Али Химический Али 12 ноября 2008 в 10:22

Использовать при работе с Друпал "зеленые" методы – прекрасно! К счастью, ядро Друпал позволяет произвести загрузку ядра и использовать весь функционал API «вне» обычного состояния движка. Для нас это большая удача, т.к. позволяет быстро и просто перенести данные.

Создание простой ноды

При написании скрипта импорта нам потребуется произвести загрузку ядра Друпал чтобы получит ьполный доступ к API. Для этого используется вызов drupal_bootstrap($phase). При этом мы можем произвести загрузку до определенного этапа, задав аргумент $phase. Значение этого параметра задает параметры конфигурации сайта, базы данных, модулей и прочего функционала. Мы используем вызов вида drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL) для получения полного доступа к API.

Внимане: Удостоверьтесь, что создали свой скрипт в корневой директории Друпал.


<?php
// Bootstrap Drupal
require 'includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
?>

Далее простой пример, создающий обычный объект node и сохраняющий его в базе данных Друпал с помощью функции node_save().


<?php
// Construct the new node object.
$node = new stdClass();

// Your script will probably pull this information from a database.
$node->title "My imported node";
$node->body "The body of my imported node.\n\nAdditional Information";
$node->type 'story';   // Your specified content type
$node->created time();
$node->changed $node->created;
$node->status 1;
$node->promote 1;
$node->sticky 0;
$node->format 1;       // Filtered HTML
$node->uid 1;          // UID of content owner
$node->language 'en';
// If known, the taxonomy TID values can be added as an array.
$node->taxonomy = array(2,3,1,);

node_save($node);
?>
Аватар пользователя Химический Али Химический Али 12 ноября 2008 в 10:29

Создание более сложных нод

Приведенный выше сценарий создаст новую ноду с названием и телом (текстом), которая будет иметь статус «опубликовано» и помещена на главную страницу. Однако процесс будет немного более сложным, если формат импортируемых данных выходит за рамки пары «заголовок-текст». Использование модуля ССК — популярный способ расширения нод путем добавления необходимого числа различных полей. Когда Друпал показывает ваш контент, ССК добавляет настраиваемые поля к объекту node, используя ловушку hook_nodeapi(). Как же выяснить структуру этих нестандартных полей? Очень просто. Для этого используется модуль Devel.

Аватар пользователя Химический Али Химический Али 12 ноября 2008 в 10:54

Использование модуля Devel

Модуль Devel позволяет с большим удобством просматривать структуру объекта node, что имеет неоценимое значение. После установки модуля откройте ноду и увидите новые вкладки «Dev load» and «Dev render». Кликните на вкладке Dev load и выберите там "... (Object) stdClass". Откроется определение объекта node, в котором мы без труда найдем уже знакомые нам данные (напр. nid, type и др.). А ниже мы увидим ряд других определений с префиксом «field_». Это и есть поля ССК, которые мы создали для нашего типа ноды.

В зависимости от того, какие сск-поля вы создали, наш сценарий импорта может выглядеть примерно так:

<?php
$node
->field_text_field[0]['value'] = "value 1";
$node->field_text_field[1]['value'] = "2nd value";
$node->field_nodereference[0]['nid'] = 58;
?>

Добавив присвоения такого типа в скрипт импорта, мы уже имеем наглядное представление о мощи API Друпал. Допустим, вы мигрируете из другой CMS с каким-то набором зависимых полей, категорий, изображений и проч. Вы можете расширить этот сценарий, предусмотрев пересмотр старой базы данных и учитывая зависимость тех или иных элементов к соответствующему объекту node.

Запустите полученный скрипт на выполнение и все ваши данные легко окажутся в Drupal! Основная прелесть использования API состоит в том, что она принимает на себя все заботы, начиная от индексации содержимого до создания url-псевдонимов, а также прочие мелочи, которые вы могли упустить.

Миграция в Друпал может показаться сложной задачей, но на самом деле все намного проще, чем кажется. Если вам понадобится импортировать 100 нод или даже 100 тысяч, надлежащее использование сценариев импорта может превратить процесс перехода в легкое дуновение ветерка!

Спасибо за внимание. Кому не западло - можете в отдельный матриал стянуть.

Аватар пользователя direqtor direqtor 12 ноября 2008 в 10:42

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

Аватар пользователя vasko vasko 12 ноября 2008 в 15:20

Помог бы мне совет с чего начать перенос нашего сайта, даже не знаю с чего начать и какие тут модули нужны :(.
Поможите советом.
Друпал установил, но система с одной стороны достаточно продумана и приспособлена для того чтоб ее наращивать, но с другой стороны вообще не приспособлена для быстрого понимания ее новичком.
Хотелось бы перевести наш сайт www.integrapro.ru на Друпал, я даже не боюсь той рутины, которая может быть проделать руками по переносу информационного наполнения. Я просто не знаю, как при помощи Друпал сделать нечто похожее и какие для этого нужно использовать модули.
Буду рад совету.

Аватар пользователя Valeratal Valeratal 18 ноября 2008 в 20:36

спасибо, полезно
вот вопрос возник
вставка таксономии, обязательно в конце, или можно перед вставкой тела ноды?

Аватар пользователя penexe penexe 18 ноября 2008 в 20:44

"Valeratal" wrote:
вставка таксономии, обязательно в конце, или можно перед вставкой тела ноды?

без разницы

Аватар пользователя Valeratal Valeratal 19 ноября 2008 в 9:53

 $node->language = 'en';
тут какой язык указываем для русскоязычного сайта?
ru ?

и еще вопрос, а если вставляем несколько нод, тогда, файл должен выглядеть так?

<?php
// Bootstrap Drupal
require 'includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);

// Construct the new node object.
$node = new stdClass();

// Your script will probably pull this information from a database.
$node->title = "My imported node";
$node->body = "The body of my imported node.\n\nAdditional Information";
$node->type = 'story';   // Your specified content type
$node->created = time();
$node->changed = $node->created;
$node->status = 1;
$node->promote = 1;
$node->sticky = 0;
$node->format = 1;       // Filtered HTML
$node->uid = 1;          // UID of content owner
$node->language = 'en';
// If known, the taxonomy TID values can be added as an array.
$node->taxonomy = array(2,3,1,);

node_save($node);

///2-ая нода

// Construct the new node object.
$node = new stdClass();

// Your script will probably pull this information from a database.
$node->title = "My imported node";
$node->body = "The body of my imported node.\n\nAdditional Information";
$node->type = 'story';   // Your specified content type
$node->created = time();
$node->changed = $node->created;
$node->status = 1;
$node->promote = 1;
$node->sticky = 0;
$node->format = 1;       // Filtered HTML
$node->uid = 1;          // UID of content owner
$node->language = 'en';
// If known, the taxonomy TID values can be added as an array.
$node->taxonomy = array(2,3,1,);

node_save($node);

?>

Аватар пользователя Химический Али Химический Али 19 ноября 2008 в 10:24

"Valeratal" wrote:
и еще вопрос, а если вставляем несколько нод, тогда, файл должен выглядеть так?

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

Аватар пользователя Valeratal Valeratal 19 ноября 2008 в 10:35

не совсем понял, однако подозреваю, что если нужно импортировать тысячи нод, то лучше делать через импорт дампа SQL базы

Аватар пользователя penexe penexe 19 ноября 2008 в 10:55

"Valeratal" wrote:
не совсем понял, однако подозреваю, что если нужно импортировать тысячи нод, то лучше делать через импорт дампа SQL базы

а зачем ноды этим способом импортировать? это решение в основном для переноса контента с УГ на Дру
ну и когда парсиш тож юзать))

Аватар пользователя Valeratal Valeratal 19 ноября 2008 в 11:36

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

Аватар пользователя penexe penexe 19 ноября 2008 в 12:31

"Valeratal" wrote:
есть куча статей в html, как их залить в друпал. Один вариант - этот скрипт, но если в него вставить все, то мм, может и не потянуть сервер.

запускаешь сайт локально), далее запоминаешь значения nid , импортируешь статьи потом делаешь дамп и заливаешь обратно на хост, а сайт на это время можно в состояние обслуживания ввести

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

Аватар пользователя Tremor Tremor 4 декабря 2008 в 2:00

странно. вроде все сделал по инструкции, однако нода не сохраняется в базе данных.
при этом никаких ошибок нет (по крайней мере пхп не ругается, может у друпала есть свой собственный лог с ошибками?). не подскажете, в чем может быть дело?
если сделать print_r($node), получаем примерно следующее:

stdClass Object
(
    [title] =>     какой-то заголовок 
    [body] => какой-то текст
    [type] => citation
    [created] => 1106033098
    [changed] => 1106033098
    [status] => 1
    [promote] => 1
    [sticky] => 0
    [format] => 1
    [uid] => 1
    [language] => ru
)

Однако, node_save($node); после этого запись в бд не добавляет Sad

Аватар пользователя cmdhitman cmdhitman 16 января 2009 в 11:26

А можно поподробнее как организовать цикл, который переберёт значения из старой базы в базу Drupal - у меня чё та не получается - начинающий пока в php -вот что я пишу

 $link = mysql_connect("localhost", "admin", "");
 if(!$link) {echo "bad connect";}
 mysql_select_db("furgan");
 $result = mysql_query("SELECT DISTINCT t3.ENTERPRISE
FROM ENTERP__RUBRIKA AS t1, PARTITION__RUBRIKA AS t2, ENTERPRISE AS t3
WHERE t1.RUBRIKA_ID = t2.RUBRIKA_ID
AND t1.ENTERPRISE_ID = t3.ENTERPRISE_ID
AND t2.PARTITION_ID =9484"
);
if(!result) {echo "very bad";}
while ($row = mysql_fetch_array($result)){

 // Construct the new node object.
$node = new stdClass();

// Your script will probably pull this information from a database.
$node->title = echo ".$row[ENTERPRISE].";
$node->body = "The body of my imported node.\n\nAdditional Information";
$node->type = 'story';   // Your specified content type
$node->created = time();
$node->changed = $node->created;
$node->status = 1;
$node->promote = 1;
$node->sticky = 0;
$node->format = 1;       // Filtered HTML
$node->uid = 1;          // UID of content owner
$node->language = 'en';
// If known, the taxonomy TID values can be added as an array.
$node->taxonomy = array(2,3,1,);

node_save($node);

}
mysql_close($link);

пишет ошибка вот здесь $node->title = echo ".$row[ENTERPRISE].";

Помогите пожалуйста - а то уже голову сломал
select работает (то есть извлекает нормальна)

Аватар пользователя cmdhitman cmdhitman 15 января 2009 в 15:26

Спасибо, Али - но всё равно пишет ошибку Parse error: syntax error, unexpected T_ECHO in R:\home\portal\www\migration.php on line 21 То есть вот здесь $node->title = echo ".$row[ENTERPRISE]."; Что я делаю не так ?

Аватар пользователя cmdhitman cmdhitman 15 января 2009 в 20:51

Переписал код вот так - почему-то в базу в таблице title выводит пустые значения - а остальные заполняются автоматом - что делать - тепреь точно не знаю Sad

<?php
 // Bootstrap Drupal
require 'includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);

 $link = mysql_connect("localhost", "admin", "89091790608");
 if(!$link) {echo "bad";}
 mysql_select_db("furgan");
 $result = mysql_query("SELECT DISTINCT t3.ENTERPRISE
FROM ENTERP__RUBRIKA AS t1, PARTITION__RUBRIKA AS t2, ENTERPRISE AS t3
WHERE t1.RUBRIKA_ID = t2.RUBRIKA_ID
AND t1.ENTERPRISE_ID = t3.ENTERPRISE_ID
AND t2.PARTITION_ID =9484"
);
if(!result) {echo "bad";}
while ($row = mysql_fetch_object($result)){

    $node = new stdClass();

// Your script will probably pull this information from a database.
$node->title = $row->ENTERPRISE;
echo $row->ENTERPRISE.'<br>';
$node->body = "The body of my imported node.\n\nAdditional Information";
$node->type = 'katalog';   // Your specified content type
$node->created = time();
$node->changed = $node->created;
$node->status = 1;
$node->promote = 1;
$node->sticky = 0;
$node->format = 1;       // Filtered HTML
$node->uid = 1;          // UID of content owner
$node->language = 'en';
// If known, the taxonomy TID values can be added as an array.

node_save($node);
         
   

}

mysql_close($link);

?>

Аватар пользователя cmdhitman cmdhitman 16 января 2009 в 11:37

В общем заносятся только титлы только с английской раскладкой - кодировка у базы utf8 - вот так задачка - в чём может быть дело ?

Аватар пользователя Химический Али Химический Али 16 января 2009 в 15:00

а скрипт в какой кодировке?

У меня так (база в win1251)

require 'includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);

function cp1251_to_utf8_recursive(/*mixed*/ $data)  
{  
    if (is_array($data))  
    {  
        $d = array();  
        foreach ($data as $k => &$v)  
        {  
            $d[cp1251_to_utf8_recursive($k)] = cp1251_to_utf8_recursive($v);  
        }  
        return $d;  
    }  
    if (is_string($data)) return iconv('cp1251', 'utf-8//IGNORE//TRANSLIT', $data);  
    if (is_scalar($data) or is_null($data)) return $data;  
    #throw warning, if the $data is resource or object:  
    trigger_error('An array, scalar or null type expected, ' . gettype($data) . ' given!', E_USER_WARNING);  
    return $data;  
}  

$link = mysql_connect("localhost", "user", "pass");
mysql_select_db("dnk73");

mysql_query("SET NAMES UTF8");
$result = mysql_query("SELECT * FROM table_News ORDER BY Id");

while ($row = mysql_fetch_array($result)){
        // Construct the new node object.
        $node = new stdClass();
        // Your script will probably pull this information from a database.
        $node->title = $row['nTitle'];
        $content = cp1251_to_utf8_recursive($row['nContent']);
        $node->teaser = substr ($content, 0, strpos($content, '</P>')+4);
        $node->body = $content;

> 700 записей влетают за 3 секунды, кодировка нормальная. Старое поле nContent - BLOB

Аватар пользователя cmdhitman cmdhitman 18 января 2009 в 16:01

В общем проблема решается ещё более проще - нужно было всего лишь вставить mysql_query("SET NAMES utf8"); сразу же после установки соединения с базой

<?php
 require 'includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
 
 $link = mysql_connect("localhost", "username", "password");
mysql_query("SET NAMES utf8");
mysql_select_db("furgan");
$result = mysql_query("SELECT DISTINCT t3.ENTERPRISE
FROM ENTERP__RUBRIKA AS t1, PARTITION__RUBRIKA AS t2, ENTERPRISE AS t3
WHERE t1.RUBRIKA_ID = t2.RUBRIKA_ID
AND t1.ENTERPRISE_ID = t3.ENTERPRISE_ID
AND t2.PARTITION_ID =9484"
);
 
while ($row = mysql_fetch_array($result)){
        // Construct the new node object.

        $node = new stdClass();
        // Your script will probably pull this information from a database.
       
$node->title = $row['ENTERPRISE'];
echo $row['ENTERPRISE'];
$node->created = time();
$node->type = "katalog"
$node->changed = $node->created;
$node->status = 1;
$node->promote = 1;
$node->sticky = 0;
$node->format = 1;       // Filtered HTML
$node->uid = 1;          // UID of content owner
$node->language = 'en';

node_save($node);      

}

Аватар пользователя ucTok_Alex@drupal.org ucTok_Alex@drup... 10 февраля 2009 в 11:50

даже незнаю куда лучше "воткнуть".
Дело в том что в оригинальной статье почему-то не вызвали [ru-api=node_object_prepare]node_object_prepare[/ru-api]

А без этого - всякие флаги приходится указывать явно (а не брать дефолтные настройки из типа). В частности - в это статье например $node->comment не удостоился даже комментария.
+модули повешенные на [ru-api=hook_prepare]hook_prepare[/ru-api] - так же останутся за бортом.

+ хотябы комментарием надо упомянуть что если испольузется auto_nodetitleто перед node_save хорошо бы вызвать auto_nodetitle_set_title($node);
ибо модуль работает через [ru-api=node_form_submit]node_form_submit[/ru-api] и при скриптовом создании - остаётся за бортом.

Чмаке пупсеги.
Аватар пользователя Serg_M Serg_M 28 марта 2009 в 12:21

Вроде данное решение пригодно, чтобы сразу после создания ноды типа Master, автоматически создавалась нода типа Slave (в которой будут кое-какие значения из родителя). А куда и как вставить вызов этого скрипта из Master? И я правильно понял, что скрипт - просто файл любое_имя.php в корневом каталоге?

Аватар пользователя wazzup wazzup 29 июня 2009 в 20:04

вот так примерно будет выглядеть тело цикла если у вас есть поле типа filefield

$mime = 'image/jpeg';
$file_drupal_path =  "sites/default/files/".$row["large"];

$file = new stdClass();
$file->filename = basename($file_drupal_path);
$file->filepath = $file_drupal_path;
$file->filemime = $mime;
$file->filesize = filesize($file_drupal_path);
$file->uid = 1;
$file->status = FILE_STATUS_PERMANENT;
$file->timestamp = time();
drupal_write_record('files', $file);
$file->fid = db_result(db_query("SELECT fid FROM {files} WHERE filepath = '%s'", $file->filepath));
$node = new stdClass();
$node->title = $row['caption'];
$node->created = time();
$node->type = "upholstery";
node_object_prepare($node);
$node->language = 'ru';

$node->field_texture = array(
   array(
      'fid' => $file->fid,
      'title' => basename($file->filename),
      'filename' => $file->filename,
      'filepath' => $file->filepath,
      'filesize' => $file->filesize,
      'mimetype' => $mime,
      'description' => basename($file->filename),
      'list' => 1,
   ),
);
node_save($node);