Работа в Drupal с несколькими базами данных. Drupal работа с базой данных


Drupal 7: работа с базой данных

В своем стремлении к абстракции от конкретной БД разработчики Drupal, похоже, неплохо так выворачивают извилины. Разработчикам модулей приходится тоже изворачиваться. Ниже приведены отличия в запросах к БД между 6-й и 7-й версиями Drupal.

Теперь различают статический запрос (static query) и динамический запрос (dynamic query). Примеры приведены ниже.

Обычно методы запроса возвращают объект SelectQuery, что позволяет использовать цепочку вызовов вроде db_select()->method1()->method2().

//**** выборка всех значений по условию, в результате получаем массив объектов //**** затем используем foreach ($nodes as $node) { ... } //**** в особо ответственных случаях необходимо использовать addTag('node_access') //**** для проверки прав на исполнение этого запроса // Drupal 6 $nodes = db_query("SELECT nid, title FROM {node} WHERE type = '%s' AND uid = %d", 'page', 1);   // Drupal 7, статический запрос $nodes = db_query(" SELECT nid, title FROM {node} WHERE type = :type AND uid = :uid ", array(':type' => 'page', ':uid' => 1))->fetchAll();   // Drupal 7, динамический запрос $nodes = db_select('node', 'n') ->fields('n', array('nid', 'title')) ->condition('n.type', 'page') ->condition('n.uid', 1) ->addTag('node_access') ->execute() ->fetchAll();   //**** получение единственной записи // Drupal 6 $title = db_result(db_query("SELECT title FROM {node} WHERE nid = %d", 123));   // Drupal 7, статический запрос $title = db_query("SELECT title FROM {node} WHERE nid = :nid", array(':nid' => 123))->fetchField();   // Drupal 7, динамический запрос $title = db_select('node', 'n') ->fields('n', array('title')) ->condition('n.nid', 123) ->execute() ->fetchField();   //**** получение объекта по его id // Drupal 6 $node = db_fetch_object(db_query("SELECT * FROM {node} WHERE nid = %d", 123));   // Drupal 7, статический запрос $node = db_query("SELECT * FROM {node} WHERE nid = :nid", array(':nid' => 123))->fetchObject();   // Drupal 7, динамический запрос $node = db_select('node', 'n') ->fields('n') ->condition('n.nid', 123) ->execute() ->fetchObject();   //**** использование INNER JOIN //**** Тут необходимо помнить, что некоторые методы (например джоины) не возвращают объект SelectQuery, //**** и поэтому их нельзя использовать в цепочке вызовов. // Drupal 6 $nodes = db_query("SELECT n.title, u.name FROM {node} n INNER JOIN {users} u ON n.uid = u.uid");   // Drupal 7, статический запрос $nodes = db_query("SELECT n.title, u.name FROM {node} n INNER JOIN {users} u ON n.uid = u.uid ")->fetchAll();   // Drupal 7, динамический запрос $query = db_select('node', 'n'); $query->innerJoin('users', 'u', 'n.uid = u.uid'); $query->fields('n', array('title')); $query->fields('u', array('name')); $nodes = $query->execute()->fetchAll();   //**** поиск минимального значения // Drupal 6 $min = db_result(db_query("SELECT MIN(fieldname) FROM {table}"));   // Drupal 7, статический запрос $min = db_query("SELECT MIN(fieldname) FROM {table}")->fetchField();   // Drupal 7, динамический запрос $query = db_select('table'); $query->addExpression('MIN(fieldname)'); $min = $query->execute()->fetchField();   //**** выборка заданного количества записей // Drupal 6 $nodes = db_query("SELECT * FROM {node} LIMIT 0, 10");   // Drupal 7, статический запрос $nodes = db_query("SELECT * FROM {node} LIMIT 0, 10")->fetchAll();   // Drupal 7, динамический запрос $nodes = db_select('node', 'n') ->fields('n') ->range(0, 10) ->execute() ->fetchAll();   //**** подсчет количества записей // Drupal 6 $count = db_result(db_query("SELECT COUNT(*) FROM {node} n WHERE n.uid = 1"));   // Drupal 7, статический запрос $count = db_query("SELECT COUNT(*) FROM {node} n WHERE n.uid = 1")->fetchField();   // Drupal 7, динамический запрос, вариант 1 $count = db_select('node', 'n') ->condition('n.uid', 1) ->countQuery() ->execute() ->fetchField();   // Drupal 7, динамический запрос, вариант 2 $query = db_select('node'); $query->addExpression('COUNT(*)'); $count = $query->execute()->fetchField();   //**** использование логического оператора OR // Drupal 6 $nodes = db_query("SELECT * FROM {node} WHERE uid = %d OR status = %d", 1, 0);   // Drupal 7, статический зспрос $nodes = db_query("SELECT * FROM {node} WHERE uid = :uid OR status = :status", array(':uid' => 1, ':status' => 0))->fetchAll();   // Drupal 7, динамический запрос $nodes = db_select('node', 'n') ->fields('n') ->condition( db_or() ->condition('uid', 1) ->condition('status', 0) )->execute() ->fetchAll();   //**** использование оператора IN $nds = array(1, 2, 3); // Drupal 6 $nodes = db_query("SELECT * FROM {node} WHERE nid IN (" . db_placeholders($nds) . ")", $nds);   // Drupal 7, статический запрос $nodes = db_query("SELECT * FROM {node} WHERE nid IN (:nds)", array(':nds' => $nds))->fetchAll();   // Drupal 7, динамический запрос $nodes = db_select('node', 'n') ->fields('n') ->condition('n.nid', $nds, 'IN') ->execute() ->fetchAll();   //**** использование оператора LIKE // Drupal 6 $nodes = db_query("SELECT * FROM {node} WHERE title LIKE '%%%s%%'", 'substring');   // Drupal 7, статический запрос $nodes = db_query("SELECT * FROM {node} WHERE title LIKE :title", array(':title' => '%' . db_like('substring') . '%'))->fetchAll();   // Drupal 7, динамический запрос $nodes = db_select('node', 'n') ->fields('n') ->condition('n.title', '%' . db_like('substring') . '%', 'LIKE') ->execute() ->fetchAll();   //**** использование оператора BETWEEN // Drupal 6 $nodes = db_query("SELECT * FROM {node} WHERE nid BETWEEN %d AND %d", 123, 456);   // Drupal 7, статический запрос $nodes = db_query("SELECT * FROM {node} WHERE nid BETWEEN :nid1 AND :nid2", array(':nid1' => 123, ':nid2' => 456))->fetchAll();   // Drupal 7, динамический запрос $nodes = db_select('node', 'n') ->fields('n') ->condition('n.nid', array(123, 456), 'BETWEEN') ->execute() ->fetchAll();   //**** сложные условия в WHERE: // Drupal 6 $nodes = db_query("SELECT * FROM {node} WHERE YEAR(FROM_UNIXTIME(created)) = %d", 2011);   // Drupal 7, статический запрос $nodes = db_query("SELECT * FROM {node} WHERE YEAR(FROM_UNIXTIME(created)) = :created", array(':created' => 2011))->fetchAll();   // Drupal 7, динамический запрос $nodes = db_select('node', 'n') ->fields('n') ->where('YEAR(FROM_UNIXTIME(n.created)) = :created', array(':created' => 2011)) ->execute() ->fetchAll();   //**** проверка значения на NULL // Drupal 6, Drupal 7 статический запрос $result = db_query("SELECT * FROM {table} WHERE field IS NULL");   // Drupal 7, динамический запрос, вариант 1 $result = db_select('table', 't') ->fields('t') ->condition('t.field', NULL, 'IS NULL') ->execute();   // Drupal 7, динамический запрос, вариант 2 $result = db_select('table', 't') ->fields('t') ->isNull('t.field') ->execute();   //**** сортировка // Drupal 6 $nodes = db_query("SELECT * FROM {node} ORDER BY created DESC, title ASC");   // Drupal 7, статический запрос $nodes = db_query("SELECT * FROM {node} ORDER BY created DESC, title ASC")->fetchAll();   // Drupal 7, динамический запрос $nodes = db_select('node', 'n') ->fields('n') ->orderBy('n.created', 'DESC') ->orderBy('n.title', 'ASC') ->execute() ->fetchAll();

В INSERT по прежнему можно использовать drupal_write_record()

543103.vsesovety.info

Работа в Drupal с несколькими базами данных

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

Находим в папке sites/default файл settings.php.Редактируем его. Вместо строчки

$db_url = 'mysql://username:password@localhost/databasename';

ставим

$db_url = array(  'default'=>'mysql://username:pass@localhost/databasename',  'db1'=>'mysql://username1:pass@host1/databasename1',  'db2'=>'mysql://username2:pass@host2/databasename2',/***  Сколько угодно параметров для требуемого количества баз данных**  Индексы кроме 'default' могут быть любыми.  */);

Теперь если в сниппете, модуле, блоке или материале вам понадобятся данные из других баз, используем следующий код:/*** Делаем активной базу с параметрами под индексом 'db1'*/db_set_active('db1');$result = db_query("Здесь нужный вам запрос к таблицам в db1")/* **  Здесь обрабатываем результат первого запроса*/// Делаем активной базу с параметрами под индексом 'db2'db_set_active('db2');$result = db_query("Здесь нужный вам запрос к таблицам в db2")/* **  Здесь обрабатываем результат второго запроса*/

/***  В конце ОБЯЗАТЕЛЬНО делаем активной «родную» базу,**  чтобы Drupal мог нормально завершить обработку страницы.*/db_set_active('default');

Переключаться между базами можно сколько угодно раз – после первого обращения Drupal кеширует ресурс соединения с БД в массиве $db_conns и повторного соединения не производится.

Если вам недоступно редактирование файла установок, то можно установить требуемое соединение сразу в PHP-коде:

/*** Получаем глобальные переменные Drupal*/global $db_url;/*** Добавляем свою строку подключения к БД, а родную оставляем под индексом 'default'*/$db_url = array(   "default"=>$db_url,   "db1"=>"mysql://username1:pass@host1/databasename1");/*** Делаем активной базу с параметрами под индексом 'db1'*/db_set_active('db1');$result = db_query("Здесь нужный вам запрос к таблицам в db1")/* **  Здесь обрабатываем результат запроса*/

/***  В конце ОБЯЗАТЕЛЬНО делаем активной «родную» базу,**  чтобы Drupal мог нормально завершить обработку страницы.*/db_set_active('default');

Указанные решения работают в D5 и D6.

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

$db_url = array(  'default'=>'mysqli://username:pass@localhost/databasename',  'db1'=>'pgsql://username1:pass@host1/databasename1',);

Вы получите: Cannot redeclare db_status_report() (previously declared in /var/www/mysite/includes/database.mysqli.inc:23) in /var/www/mysite.ru/includes/database.pgsql.inc

Устранить данное ограничение можно только хаком ядра Drupal. Хак получается весьма объемистым. С указанной ошибкой все дело не в функции db_status_report(), а со способом которым Drupal подключает интерфейс требуемого типа баз данных. Дело в том, что названия всех функций (за исключением одной – db_check_setup) находящихся в файлах database.pgsql.inc, database.mysql.inc, database.mysqli.inc и database.mysql-common.inc совпадают, что приводит к конфликту в именах 41 функции. Поэтому использовать несколько подключений к базам разных типов можно только полностью переписав слой абстракции баз данных в Drupal.

Чтобы сделать это откроем все упомянутые файлы в редакторе.

Из файлов database.mysql.inc и database.mysqli.inc удаляем строчку

require_once './includes/database.mysql-common.inc';

Содержимое файла database.mysql-common.inc копируем в файлы database.mysql.inc и database.mysqli.inc, а сам файл делаем пустым.

Далее во всех трех файлах database.pgsql.inc, database.mysql.inc, database.mysqli.inc переименовываем все функции добавляя к их именам постфикс типа базы данных: в файле database.pgsql.inc – _pgsql; в файле database.mysql.inc – _mysql; в файле database.mysqli.inc – _mysqli. Переименовывать не надо только функцию db_check_setup – она уникальна для файла database.pgsql.inc.

Открываем файл database.inc и создаем там 41(!!!) функцию со следующими именами.

_db_create_field_sql()_db_create_key_sql()_db_create_keys_sql()_db_process_field()_db_process_field()_db_query()db_add_field()db_add_index()db_add_primary_key()db_add_unique_key()db_affected_rows()db_change_field()db_column_exists()db_connect()db_create_table_sql()db_decode_blob()db_distinct_field()db_drop_field()db_drop_index()db_drop_primary_key()db_drop_table()db_drop_unique_key()db_encode_blob()db_error ()db_escape_string()db_fetch_array()db_fetch_object()db_field_set_default()db_field_set_no_default()db_last_insert_id()db_lock_table()db_query()db_query_range()db_query_temporary()db_rename_table()db_result()db_status_report()db_table_exists()db_type_map()db_unlock_tables()db_version()

Все функции выглядят однотипно, различаясь только названием.

function имя_функции () {  global $db_type;  $args = func_get_args();  return call_user_func_array("имя_функции_".$db_type, $args);}

Несомненно, большой объем правок кода ядра может отпугнуть желающих использовать это. Есть еще один способ, требующий меньшего объема кода. Основная проблема в том, что в PHP обычно нет возможности удаления или переопределения (перегрузки) функций. Правда, одно из расширений PHP – Runkit позволяет сделать это. Если runkit подключен, то достаточно сделать небольшую вставку в код функции db_set_active(). Находим строчки:

    $db_type = substr($connect_url, 0, strpos($connect_url, '://'));     $handler = "./includes/database.$db_type.inc";     if (is_file($handler)) {       include_once $handler;     }     else {       _db_error_page("The database type '". $db_type ."' is unsupported. Please use either'mysql' or 'mysqli' for MySQL, or 'pgsql' for PostgreSQL databases.");     }

    $db_conns[$name] = db_connect($connect_url);  }

и добавляем свой код:    $db_type = substr($connect_url, 0, strpos($connect_url, '://'));     $handler = "./includes/database.$db_type.inc";     if (is_file($handler)) {       $fnames = array(         '_db_create_field_sql', '_db_create_key_sql', '_db_create_keys_sql',         '_db_process_field', '_db_process_field', '_db_query',         'db_add_field', 'db_add_index', 'db_add_primary_key',         'db_add_unique_key', 'db_affected_rows', 'db_change_field',         'db_column_exists', 'db_connect', 'db_create_table_sql',         'db_decode_blob', 'db_distinct_field', 'db_drop_field',         'db_drop_index', 'db_drop_primary_key', 'db_drop_table',         'db_drop_unique_key', 'db_encode_blob', 'db_error',         'db_escape_string', 'db_fetch_array', 'db_fetch_object',         'db_field_set_default', 'db_field_set_no_default', 'db_last_insert_id',         'db_lock_table', 'db_query', 'db_query_range', 'db_query_temporary',         'db_rename_table', 'db_result', 'db_status_report',         'db_table_exists', 'db_type_map', 'db_unlock_tables', 'db_version',       );       foreach ($fnames as $fname) {         @runkit_function_remove($fname);       }       include $handler;     }     else {       _db_error_page("The database type '". $db_type ."' is unsupported. Please use either'mysql' or 'mysqli' for MySQL, or 'pgsql' for PostgreSQL databases.");     }

    $db_conns[$name] = db_connect($connect_url);  }

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

Источники:

db_set_active()runkit_function_remove()2 соединения с БДПереключение между базами

shaman.asiadata.ru

Cоздание и обновление записей в базе данных через Drupal API

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

Вставка записи:

db_query('INSERT INTO {mytable} (value1, value2) VALUES (%d, "%s")', $int, $string);

Обновление записи:

db_query('UPDATE {mytable} SET value2 = "%s" WHERE value1 = %d', $new_string, $int);

Однако хорошим тоном является использование функции из Drupal API drupal_write_record.

Вставка записи:

$row = new stdClass(); $row->value1 = $int; $row->value2 = $string; drupal_write_record('mytable', $row);

Обновление записи:

$row = new stdClass(); $row->value1 = $int; $row->value2 = $string; drupal_write_record('mytable', $row, 'value1');

Преимущества drupal_write_record:

Недостатки:

Обновление и запись в базу данных Drupal 7

Всё вышесказанное действительно и для седьмого Друпала. Однако с его выходом появился более гибкий механизм записи/обновления таблиц - db_merge(). Она знает, что надо делать с записью - вставлять или обновлять, поэтому её использование является максимально удобным. И пример для наглядности:

Запись данных в таблицу без использования db_merge:

function example_insert($name, $value1, $value2) { $row_exists = db_query( 'SELECT field1 FROM {example} WHERE name = :name', array(':name' => $name) )->fetchField(); if ($row_exists) { db_query( 'UPDATE {example} SET field1 = :value1, field2 = :value2 WHERE name = :name', array(':name' => $name, ':value1' => $value1, ':value2' => $value2) ); } else { db_query( 'INSERT INTO {example} (name, field1, field2) VALUES (:name, :value1, :value2)', array(':name' => $name, ':value1' => $value1, ':value2' => $value2) ); } }

С использованием db_merge:

function example_insert($name, $value1, $value2) { db_merge('example') ->key(array('name' => $name)) ->fields(array( 'field1' => $value1, 'field2' => $value2, )) ->execute(); }

Разница, я думаю, очевидна ;)

drupalace.ru


Prostoy-Site | Все права защищены © 2018 | Карта сайта