Работа в 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();543103.vsesovety.info
Работа в Drupal с несколькими базами данных
Если вам необходимо на друпал-сайте использовать данные из другой базы (может быть даже с другого хоста), то это достаточно просто сделать. Предоставленные для этого возможности не затрагивают кода ядра и могут быть использованы, как в виде вставок PHP-кода в материалы сайта, так и в собственных модулях и темах.
Находим в папке sites/default файл settings.php.Редактируем его. Вместо строчки
$db_url = 'mysql://username:password@localhost/databasename';
ставим/*** В конце ОБЯЗАТЕЛЬНО делаем активной «родную» базу,** чтобы Drupal мог нормально завершить обработку страницы.*/db_set_active('default');
Переключаться между базами можно сколько угодно раз – после первого обращения Drupal кеширует ресурс соединения с БД в массиве $db_conns и повторного соединения не производится.Если вам недоступно редактирование файла установок, то можно установить требуемое соединение сразу в PHP-коде:
/*** В конце ОБЯЗАТЕЛЬНО делаем активной «родную» базу,** чтобы 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_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:
- От глаз скрыты прямые запросы в базу данных
- Выполняет за вас предварительную работу с данными (сериализация, приведение типов и т.д.)
- Позволяет сэкономить время на написании своего запроса
- Уберегает от возможных ошибок в запросе
Недостатки:
- Невозможно при апдейте записать значением поля NULL
- Не работает при включении и установке модуля (hook_install, hook_enable) без дополнительного кода перед вызовом функции
- Не работает с таблицами, не описанными в hook_schema
Обновление и запись в базу данных 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