Использование ПО с открытым исходным кодом для создания Web-сайта для совместной работы: Часть 9. Освоение уровня базы данных

В статье исследуется уровень абстракции базы данных в Drupal и рассматриваются вопросы ее эффективного использования при разработке Web-сайта. Вы также узнаете о реализации необходимого кода для поддержки новой базы данных - IBM DB2 Express-C.

Элистер Льюис-Боуэн, старший инженер-программист, IBM

Элистер Льюис-БоуэнЭлистер Льюис-Боуэн (Alister Lewis-Bowen) работает старшим инженером-программистом в IBM Internet Technology Group. Он занимается Интернет и web-технологиями как сотрудник IBM UK с 1993. Элистер был переведен в США для работы над Web-сайтами спортивных событий, спонсируемых IBM, а затем как старший Web-мастер ibm.com. В настоящее время он помогает создавать семантические Web-прототипы.



Стефен Эванчик, инженер-программист, IBM

Стефен ЭванчикСтефен Эванчик (Stephen Evanchik) работает инженером-программистом в IBM Internet Technology Group. Он принимает участие во многих проектах с открытыми исходными кодами, самым известным из которых является его IBM TrackPoint-драйвер в ядре Linux. Стефен в настоящее время работает с появляющимися семантическими Web-технологиями.



Луис Вайцман, старший инженер-программист, IBM

Луис ВайцманЛуис Вайцман (Louis Weitzman) работает старшим инженером-программистом в IBM Internet Technology Group. В течение 30 лет он работал на стыке дизайна и вычислений. Помогал разрабатывать XML, фрагментированную систему управления содержимым, используемую для ibm.com, а в настоящее время участвует в обеспечении процесса проектирования новых проектов.



25.12.2006

Введение

В данной серии статей рассматривается создание специализированного Web-сайта для вымышленной компании International Business Council (IBC). Для сайта требуется создать хранилище документов, дискуссионные группы, специализированные рабочие группы, систему планирования конференций и описание запланированных сессий.

В данной статье вы исследуете уровень абстракции базы данных в Drupal, очень тонкий уровень кода, который окружает низкоуровневые PHP-подпрограммы базы данных. Drupal стандартно поставляется с поддержкой MySQL и PostgreSQL, но добавить дополнительную базу данных относительно легко, если она поддерживает PHP-интерфейс. Как разработчик модулей, вы должны как можно больше использовать этот уровень базы данных, для того чтобы уменьшить время разработки и увеличить переносимость ваших модулей.

Уровень базы данных в Drupal распределяется между двумя основными файлами. Первый файл, includes/database.inc, определяет функции, не являющиеся специфичными для конкретной реализации базы данных. Этот файл содержит две функции, с которыми вы столкнетесь при разработке модулей:

db_query()Главная функция, выполняющая запросы к базе данных
db_query_range()Ограничивает результаты запроса определенным диапазоном

Второй файл, includes/database.<type>.inc, определяет все функции, обеспечивающие абстрагирование от низкоуровневых PHP-функций базы данных, специфичных для каждого типа базы данных. Drupal по умолчанию поддерживает MySQL и PostgreSQL, но можно добавить другие базы данных, просто реализуя для них функции, расположенные в includes/database.mysql.inc. К функциям, которые вы обычно будете использовать, относятся:

db_result()Возвращает отдельный результат предыдущего запроса
db_fetch_object()Возвращает следующую строку в виде PHP-объекта
db_fetch_array()Возвращает следующую строку в виде массива значений
db_num_rows()Возвращает количество строк, возвращенных предыдущим запросом
db_affected_rows()Возвращает количество строк, измененных предыдущим запросом

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

  • Система разбивки на страницы (pager), обеспечивающая механизм распределения больших наборов, полученных в результате выполнения запроса, на несколько страниц.
  • Система установки модулей, упрощающая установку и управление дополнительными объектами базы данных для сторонних модулей.

Эти системы подробно рассматриваются ниже.

Система разбивки на страницы

Многие Web-сайты имеют содержимое, отображаемое на нескольких последовательных страницах. Примером такого поведения является навигация по результатам операции поиска. Пользователь вводит критерии запроса и передает их на сайт. Если количество результатов поиска превышает обще число строк, которые могут быть выведены на одной странице, активизируется система pager. На рисунке 1 показан пример системы разбивки на страницы в действии.

Рисунок 1. Результаты поиска на Drupal Web-сайте, использующем систему разбивки на страницы
Рисунок 1. Результаты поиска на Drupal Web-сайте, использующем систему разбивки на страницы

Вы можете спросить, какое отношение это имеет к уровню абстракции данных в Drupal? Ответ: функция pager_query() использует функцию db_query_range() для выбора соответствующей страницы результатов.

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

pager_query()Передает запрос в базу данных для конкретной страницы результатов.
theme_pager()Главная функция темы для отображения запроса системы разбивки на страницы. Все другие функции темы системы разбивки на страницы используются в этой функции.
theme_pager_first()Отображает ссылку на первую страницу результатов (рисунок 2, раздел A).
theme_pager_last()Отображает ссылку на последнюю страницу результатов (рисунок 2, раздел E).
theme_pager_link()Отображает ссылку на конкретную страницу результатов (рисунок 2, все разделы).
theme_pager_list()Отображает список соседних страниц результатов (рисунок 2, раздел C).
theme_pager_next()Отображает ссылку на следующую страницу результатов (рисунок 2, раздел D).
theme_pager_previous()Отображает ссылку на предыдущую страницу результатов (рисунок 2, раздел B).
Рисунок 2. Пример элементов управления системы разбивки на страницы для перемещения по многостраничным результатам поиска
Рисунок 2. Пример элементов управления системы разбивки на страницы для перемещения по многостраничным результатам поиска

Теперь, когда мы рассмотрели компоненты системы разбивки на страницы, давайте взглянем на пример. В качестве примера мы будем использовать модуль announcement, рассмотренный в предыдущих статьях.

Пример системы разбивки на страницы

В данном примере мы хотим разрешить администратору просматривать все уведомления, введенные на Web-сайт IBC. Это схема используется очень часто, а потому является отличным примером использования системы разбивки на страницы Drupal. Мы начнем с определения URL и соответствующих элементов меню в announcement_menu(). Код приведен в листинге 1.

Листинг 1. Дополнение к announcement_menu для активизации кода системы разбивки на страницы
$items[] = array('path'     => 'announcements/pager',
                 'title'    => t('Announcements Pager Example'),
                 'access'   => user_access('administer site'),
                 'type'     => MENU_CALLBACK,
                 'callback' => 'announcement_pager');

Мы подключаем URL announcements/pager к функции announcement_pager() и разрешаем просматривать весь список уведомлений только администраторам. Теперь мы создадим код, отображающий страницу с элементами управления для навигации (листинг 2).

Листинг 2. Функция обратного вызова announcement_pager
function announcement_pager() {
  $query = "SELECT n.nid, n.created FROM {node} " .
           "n WHERE type = 'announcement' ORDER BY n.created DESC";
  $result = pager_query(db_rewrite_sql($query), 10);
  while ($announcement = db_fetch_object($result)) {
    $output .= node_view(node_load($announcement->nid), 1);
  }
  $output .= theme('pager', NULL, 10);
  return $output;
}

Этот код выдает запрос, используя систему разбивки на страницы с ограничением в 10 результатов на страницу. Если вы перейдете по URL announcements/pager, то увидите страницу, аналогичную изображенной на рисунке 3.

Рисунок 3. Уведомления с использованием системы разбивки на страницы
Рисунок 3. Уведомления с использованием системы разбивки на страницы

Система разбивки на страницы Drupal является отличным примером маленького приложения уровня абстракции базы данных. Оно использует функции db_query() и db_query_range() для обеспечения постраничных результатов для потенциально больших наборов данных.


Управление схемами базы данных модуля

В шестой части данной серии статей рассматривались шаги по созданию нового модуля для уведомлений. Модуль announcements необходим для хранения дополнительных данных в базе данных. Мы рассмотрели дополнительную таблицу базы данных и предоставили выражение SQL CREATE TABLE, использующееся для добавления таблицы в вашу базу данных. Добавление таблицы вне среды Drupal является проблематичным, поскольку затрудняет обновление или, в некоторых случаях, делает его не возможным.

Для облегчения управления модулем и предоставления четкого способа обновления разработчику модулей, Drupal обеспечивает механизм автоматического обновления базы данных через файл module.install. Этот файл содержит два фрагмента информации, которые мы рассмотрим подробно, используя в качестве примера наш модуль announcement из шестой части данной серии статей. Модуль announcement использовал SQL, приведенный в листинге 3, для добавления новой таблицы в базу данных.

Листинг 3. SQL для создания дополнительной таблицы в базе данных, поддерживающей модуль announcement
CREATE TABLE announcement (
  nid             int(10) unsigned NOT NULL default '0',
  abstract        varchar(255) default '',
  publish_date    integer NOT NULL default '0',
  expiration_date integer NOT NULL default '0',
  PRIMARY KEY (nid)
);

Создание файла .install

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

Создать файл .install легко. Просто создайте файл под названием <module name>.install и поместите его в тот же каталог, в котором расположен ваш модуль. В нашем случае имя файла - announcement.install. Теперь мы должны создать реализацию hook_install() модуля announcement. Следуйте формуле именования ловушек, рассмотренной в пятой и шестой частях данной серии статей. В листинге 4 показан скелет реализации announcement_install.

Листинг 4. Скелет функции announcement_install в файле .install
function announcement_install() {
  global $db_type;
  switch ($db_type) {
    case 'mysql':
    case 'mysqli':
      break;

    case 'pgsql':
      break;
  }
}

Эта простая ловушка содержит один блок операторов switch / case, переключающий типы базы данных. Строки mysql и mysqli указывают MySQL-совместимый код, а строка pgsql указывает PostgreSQL-совместимый код. Теперь вставьте выражение SQL для создания таблицы в оператор case для MySQL, не забывая использовать db_query(), как показано в листинге 5.

Листинг 5. Часть ловушки install с SQL-выражением для создания таблицы announcement
    case 'mysql':
    case 'mysqli':
      db_query("
        CREATE TABLE {announcement} (
        nid             int(10) unsigned NOT NULL default '0',
        abstract        varchar(255) default '',
        publish_date    integer NOT NULL default '0',
        expiration_date integer NOT NULL default '0',
        PRIMARY KEY (nid)
        );
      ");
      break;

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

Вторым изменением, которое вы заметите, является по внешнему виду не правильное SQL-выражение, использованное для имени таблицы: {announcement}. Где бы вы ни обратились к таблице в вашем SQL-коде, вы всегда должны заключать его в фигурные скобки, например: {announcement}. Это часть механизма, который позволяет администратору сайта добавить при помощи строки префикс ко всем таблицам Drupal. Например, если администратор решает, что все таблицы Drupal должны иметь префикс ibc_, название таблицы {announcement} будет расширяться в ibc_announcement вовремя вызова db_query(). Эта функциональная возможность является необходимой, если вы совместно используете базу данных в Drupal и другом приложении, а также во многих других ситуациях.

Еще один момент, могущий привести к конфузу: Эта ловушка вызывается только тогда, когда модуль разрешается первый раз на странице администрирования модуля. Таблицы базы данных модуля не удаляются при последующем запрете модуля. Если вы решили повторно разрешить его, hook_install() не будет выполняться.

Управление обновлениями схемы

Теперь, когда вы создали ловушку для установки модуля, создающую необходимые объекты базы данных, посмотрим, что произойдет, когда вам понадобится изменить эти объекты базы данных? К счастью, Drupal предоставляет еще одну ловушку hook_update_<N(), где <N> представляет собой количество обновлений (1 для первого обновления). Следовательно, первой функцией обновления для любого модуля является функция <module name>_update_1(). Эта функция обновляет версию схемы модуля и соответствующие объекты базы данных.

Каждый раз, обновляя схему базы данных модуля, например, добавляя к атрибуту модификатор NOT NULL, вы должны записать это обновление в следующей доступной функции hook_update_<N>(), увеличивая <N>. При выпуске или развертывании вашего модуля вы и все ваши пользователи могут обновить модуль до самой последней версии одним простым действием, выбрав последнюю доступную версию схемы.

Используя модуль announcement из шестой части данной серии статей, добавим еще один атрибут, указывающий важность уведомления. Назовем этот атрибут priority. Новое выражение CREATE TABLE показано в листинге 6.

Листинг 6. Обновленное создание таблицы announcement для подключения нового атрибута priority
    case 'mysql':
    case 'mysqli':
      db_query("
        CREATE TABLE {announcement} (
        nid             int(10) unsigned NOT NULL default '0',
        abstract        varchar(255) default '',
        publish_date    integer NOT NULL default '0',
        expiration_date integer NOT NULL default '0',
        priority        tinyint(2) default '0',
        PRIMARY KEY (nid)
        );
      ");
      break;

Мы должны изменить SQL в hook_install() для любых новых установок модуля announcement. Теперь мы должны предоставить нужный hook_update_<N>() для существовавших ранее установок модуля announcement. Для модуля announcement необходимый PHP-код показан в листинге 7.

Листинг 7. Первая ловушка базы данных update для модуля announcement, добавляющая атрибут priority
function announcement_update_1() {
  global $db_type;
  switch ($db_type) {
    case 'mysql':
    case 'mysqli':
      db_query('ALTER TABLE {announcement} ADD COLUMN priority 
         tinyint(2) default \'0\' ');
      break;

    case 'pgsql':
      break;
  }
}

Также как и для hook_install(), мы предоставляем отдельный оператор case для каждого типа базы данных. Обратите внимание на то, что мы все еще используем db_query() и заключаем название таблицы в скобки { и }. Мы еще раз подчеркиваем важность написания переносимого кода базы данных. Ваш модуль может использоваться многими людьми в разных ситуациях, поэтому вы должны предложить им как можно большую гибкость. Если у вас есть дополнительные обновления базы данных для новой версии модуля announcement, вы должны добавить их в функцию announcement_update_1().

Теперь, после создания всего PHP и SQL-кода поддержки для установки и обновления модуля announcement, вы должны указать Drupal выполнить обновления схемы. Это легко выполнить при помощи вашего браузера и Drupal-сайта. Сначала создайте резервную копию базы данных перед попыткой обновления ее схемы, и убедитесь, что эта резервная копия является корректной и полной. Затем войдите в систему как администратор (пользователь с uid == 1) и перейдите по адресу http://your.drupal.site/update.php. Появляющаяся страница показана на рисунке 4.

Рисунок 4. Страница обновления Drupal
Рисунок 4. Страница обновления Drupal

Выберите ссылку Run the database upgrade script (Выполнить сценарий обновления базы данных) для начала процесса обновления. Вы должны увидеть экран, аналогичный показанному на рисунке 5. Ваша установка Drupal может иметь большее число ниспадающих списков выбора, зависящее от количества установленных вами модулей. Поскольку мы обновляем модуль announcements, убедитесь в том, что в его ниспадающем списке выбран самый большой номер версии, затем нажмите Update. Drupal обрабатывает все обновления модуля, начиная с установленной версии и заканчивая выбранной вами версией.

Рисунок 5. Страница обновления установки IBC
Рисунок 5. Страница обновления установки IBC

Разверните раздел updates и проверьте, что выбрано обновление, которое вы только что создали для модуля announcement. Затем нажмите кнопку Update. Если вы видите какие-либо ошибки, восстановите вашу базу данных из созданной резервной копии и попробуйте снова.

Как описывалось ранее, когда модуль разрешается первый раз на странице администрирования модуля, выполняется функция hook_install(), и создаются таблицы базы данных. Drupal установит также версию схемы установленного модуля в самое большое значение пронумерованных hook_update_<N>(). Это указывает на то, что модуль установлен и имеет новейшую версию.

Хотя данное обсуждение функций файла .install сконцентрировано на уровне базы данных, вы не ограничены установкой только структуры базы данных. Если ваш модуль требует дополнительной инициализации и обновлений, поместите элементы инициализации в hook_install() или hook_update_<N>(). Это может быть добавление переменных Drupal, создание словаря с набором терминов по умолчанию, либо что-нибудь еще, что вы сможете придумать.


Поддержка переносимости базы данных

Уровень абстракции базы данных в Drupal является тонким наружным слоем над PHP-функциями базы данных. Это хорошо с точки зрения производительности и сложности, но может соблазнить вас на написание непереносимого кода базы данных. Когда мы используем термин переносимость базы данных, то имеем в виду код, который корректно использует уровень абстракции базы данных Drupal в дополнение к написанию SQL-выражений, работающих с несколькими базами данных. Ваш Drupal-модуль может использоваться в разных ситуациях и конфигурациях, поэтому важно проектировать его хорошо и планировать все заранее.

В следующих примерах показаны различия между хорошими и плохими вызовами базы данных.

Названия таблиц

Листинг 8. Некорректно: использование реальных названий таблиц
db_query("SELECT * FROM node");
Листинг 9. Корректно: заключение названий таблиц в фигурные скобки для возможности указания префикса
db_query("SELECT * FROM {node}");

Drupal разрешает администратору добавлять префиксы для таблиц. Префиксы позволяют администратору организовать совместное использование таблиц двумя Drupal-сайтами, иметь более одного Drupal-сайта, содержащегося в одной базе данных, а при использовании нескольких сред хостинга лучше организовать их базы данных. Если администратор установил префикс drupal_, тогда таблица будет иметь название drupal_node, и запрос из первого примера не выполнится, поскольку таблицы node не существует.

Запрос в листинге 9 будет принимать любые установки префикса таблиц базы данных, которые установит администратор Drupal-сайта. Это простое изменение очень важно тогда, когда ваш модуль используется в полной установке Drupal или в системах хостинга, ограничивающих функции базы данных.

Встроенные параметры

Листинг 10. Некорректно: встраивание параметров непосредственно в строку запроса
db_query("SELECT * FROM {node} WHERE nid = $nid");
Листинг 11. Корректно: Использование "заполнителей" переменных, установленных в соответствующий тип данных
db_query("SELECT * FROM {node} WHERE nid = %d", $nid);

Главной проблемой такого подхода является ситуация, когда переменная $nid содержит какие-либо специальные символы, например ' или ", и вы можете стать более уязвимыми для атаки типа SQL-инъекции (когда злоумышленник пытается получить дополнительную информацию из базы данных для разных целей). Чтобы это предотвратить, вы должны исключить все специальные символы перед отправкой их в базу данных. К сожалению, методы выполнения этого действия различны для разных баз данных. Это означает, что вы должны были бы знать, какой тип базы данных использует Drupal и, соответственно, настроить ваш код. Но, к счастью, Drupal обрабатывает все это сам, если вы корректно используете функцию db_query().

В листинге 11 в переменной $nid специальные символы будут замещены корректными значениями согласно правилам базы данных.

Диапазон значений

Листинг 12. Некорректно: встраивание предложения LIMIT MySQL в ваш запрос
db_query("SELECT * FROM {node} WHERE nid = %d LIMIT 1, 10", $nid);
Листинг 13. Корректно: использование db_query_range() для выбора диапазона значений из базы данных
db_query_range("SELECT * FROM {node} WHERE nid = %d", $nid, 1, 10);

Предложение LIMIT не является частью стандарта SQL и не является переносимым для всех баз данных. Например, этот запрос не будет работать в DB2 Express-C, и все модули, использующие запрос такой формы, должны быть переписаны для обеспечения возможности использования.

Запрос в листинге 13 использует специфичный для любой базы данных SQL-запрос для извлечения первых 10 строк в наборе данных.

Это только некоторые примеры передового опыта использования базы данных в Drupal. По мере развития Drupal развиваются также его уровень базы данных и лучшие методы его использования.


IBM DB2 Express-C

DB2 Express-C - это версия DB2 для сообщества. Она является полнофункциональной версией сервера базы данных DB2, которая может использоваться в производственной среде и для разработки. Существуют определенные ограничения на количество ресурсов, которые могут быть использованы (до 2 двухядерных CPU, до 4GB RAM), но других ограничений нет. Ссылки на дополнительную информацию по DB2 Express-C приведены в разделе "Ресурсы".

Добавление поддержки DB2 Express-C в Drupal является хорошим способом подробного изучения уровня абстракции базы данных. Мы также можем увидеть, насколько хорошо работает уровень абстракции при реализации третьей базы данных. В следующем разделе мы кратко рассмотрим, как установить DB2 Express-C, и как мы создали необходимый код для Drupal. Важно понимать, что этот код является только отправной точкой для сообщества и не имеет законченной реализации.

Установка

После загрузки установочного пакета DB2 Express-C на вашу локальную систему разархивируйте его и выполните двойной щелчок кнопкой мыши на файле db2setup.exe для начала процесса установки. Вы должны увидеть панель, изображенную на рисунке 6.

Рисунок 6. Панель приглашения IBM DB2 Express-C
Рисунок 6. Панель приглашения IBM DB2 Express-C

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

Рисунок 7. Выбор типа установки
Рисунок 7. Выбор типа установки

Выберите установку, файл характеристик (response file) или то и другое, как показано на рисунке 8. Затем нажмите кнопку Next.

Рисунок 8. Выбор установки, файла характеристик или и того, и другого
Рисунок 8. Выбор установки, файла характеристик или и того, и другого

Выберите папку для установки, как показано на рисунке 9, и нажмите кнопку Next.

Рисунок 9. Выбор папки для установки
Рисунок 9. Выбор папки для установки

Введите имя пользователя и пароль административного сервера, как показано на рисунке 10. Нажмите кнопку Next для продолжения.

Рисунок 10. Установка информации о пользователе для DB2 Administration Server
Рисунок 10. Установка информации о пользователе для DB2 Administration Server

На рисунке 11 показано, как настроить экземпляр DB2. Нажмите кнопку Next для продолжения.

Рисунок 11. Настройка экземпляров DB2
Рисунок 11. Настройка экземплярjd DB2

На рисунке 12 показано последнее диалоговое окно перед началом процесса установки. Нажмите кнопку Finish для начала копирования файлов.

Рисунок 12. Начало копирования файлов и создание файла характеристик
Рисунок 12. Начало копирования файлов и создание файла характеристик

Диалоговое окно, показанное на рисунке 13, позволяет создать профиль браузера First Steps.

Рисунок 13. Создание профиля браузера DB2 First Steps
Рисунок 13. Создание профиля браузера DB2 First Steps

Установка IBM DB2 Express-C завершена.

Настройка DB2 и PHP

Мы должны установить расширение для PHP перед получением возможности общаться с базой данных DB2. Существует два метода подключения к DB2 из PHP. Первый метод использует интерфейс прикладного программирования (application program interface - API) Open Database Connectivity (ODBC) PHP и совместимый с ODBC модуль, специализированный для базы данных. Этот метод является общим и переносимым, но имеет пониженную производительность.

Второй метод - использовать родной DB2-модуль, который использует интерфейс DB2 Call Level Interface (CLI) и общается с базой данных напрямую. Применение этого модуля позволяет использовать преимущества любых специализированных DB2-функций, одновременно предоставляя Drupal database API. Ссылки на дополнительную информацию по этому модулю приведены в разделе "Ресурсы".

Установить этот модуль просто, но вы должны следовать инструкциям, приведенным на справочной странице модуля (если вы не знаете, как установить PHP-расширения, обратитесь к разделу "Ресурсы" для получения дополнительной информации). Чтобы установить расширение PHP DB2, вы должны иметь версию DB2, установленную с пакетами разработки приложений. Команды для базовой установки в системе Linux™ показаны в листинге 14.

Листинг 14. Команды для компоновки и установки расширения IBM DB2 PHP в Linux
$ cd ibm_db2
$ phpize
$ ./configure --with-IBM_DB2=/path/to/DB2
$ make
$ su - root
# make install

Эти команды инициализируют среду компоновки PHP-расширения, выполняют конфигурирование среды компоновки для использования с конкретной версией DB2, а также компилируют и устанавливают расширение. В зависимости от вашего дистрибутива ваши команды могут отличаться от приведенных в листинге 14.

Если вы используете Windows®, то можете загрузить IBM DB2 PHP-расширение.

Выберите расширение для вашей версии PHP и сохраните файл в каталоге extensions. Если вы выполнили шаги из третьей части данной серии статей, таким каталогом является C:\PHP\ext. Сразу после сохранения вашего файла добавьте строку в листинг 15 вашего файла php.ini в то место, где разрешены другие расширения.

Листинг 15. Разрешение IBM DB2 PHP-расширения
extension=php_ibm_db2.dll

После установки IBM DB2 PHP-расширения вы должны указать PHP, какой экземпляр DB2 он должен использовать. В листинге 16 показана необходимая информация, которую нужно добавить в файл php.ini.

Листинг 16. Добавление информации об экземпляре IBM DB2 в файл php.ini
ibm_db2.instance_name = <name of your instance here>

DB2 должен быть разрешен и настроен в PHP. Вы можете проверить вашу установку, отобразив список расширений, известных PHP. Вы должны увидеть в этом списке ibm_db2, как показано в листинге 17.

Листинг 17. Проверка успешной установки IBM DB2 PHP-расширения
[PHP Modules]
bcmath
calendar
com_dotnet
ctype
date
dom
ftp
hash
iconv
ibm_db2
ldap
libxml
mysql
odbc
pcre
Reflection
session
SimpleXML
SPL
standard
tokenizer
wddx
xml
xmlreader
xmlwriter
zlib

Drupal с IBM DB2 Express-C

Разрешение Drupal использовать серверную базу данных, отличную от MySQL или PostgreSQL, требует выполнения средней по объему работы. Есть две задачи, которые нужно выполнить, перед тем, как вы сможете использовать вашу базу данных с Drupal. Первая задача - сгенерировать сценарий начальной схемы базы данных. Для инициализации баз данных MySQL и PostgreSQL используются следующие файлы, соответственно:

  • database/database.4.1.mysql
  • database/database.pgsql

Эти файлы содержат определения SQL-таблиц и их начальные значения. В листинге 18 показана таблица poll для базы данных MySQL, а в листинге 19 показана она же для базы данных DB2.

Листинг 18. Таблица poll для баз данных MySQL
CREATE TABLE poll (
  nid int(10) unsigned NOT NULL default '0',
  runtime int(10) NOT NULL default '0',
  active int(2) unsigned NOT NULL default '0',
  PRIMARY KEY (nid)
)
DEFAULT CHARACTER SET utf8;
Листинг 19. Таблица poll для баз данных DB2
CREATE TABLE "POLL"  (
  "NID" INTEGER NOT NULL WITH DEFAULT 0, 
  "RUNTIME" INTEGER NOT NULL WITH DEFAULT 0, 
  "ACTIVE" INTEGER NOT NULL WITH DEFAULT 0)   
 IN "TS_DRPL"
;

Каждая база данных имеет свою собственную специфику синтаксиса. Это означает, что вы должны перевести синтаксис MySQL или PostgreSQL в синтаксис вашей базы данных.

Второй задачей является реализация PHP-кода, который обеспечивает специфичные для базы данных функции. PHP-код поддержки MySQL расположен в файле includes/database.mysql.inc. Существует более дюжины функций, которые должны быть реализованы специально для вашей базы данных. Наконец, после завершения этих задач, вы должны тщательно протестировать вашу установку Drupal, для того чтобы убедиться в том, что ваша новая база данных используется корректно.

В следующих разделах мы рассмотрим процесс и инструментальные средства, используемые для создания SQL-сценария инициализации, а также PHP-код базы данных в Drupal. Важно понимать, что это только отправная точка для разрешения Drupal работать с DB2 Express-C, которая не является полным, завершенным решением.

Преобразование схемы базы данных

Первым шагом при разрешении новой базы данных в Drupal является преобразование схемы базы данных в соответствующий формат из формата MySQL. Мы рекомендуем использовать для автоматизации этой задачи любое доступное инструментальное средство; зачем тратить часы на то, что машина может сделать за секунды? IBM Migration Toolkit (MTK) является отличным средством для выполнения этой задачи. Мы использовали MTK для успешного переноса начальной, пустой базы данных Drupal в базу данных DB2 всего за несколько минут (ссылки на дополнительную информацию о MTK и его использовании приведены в разделе "Ресурсы").

Хотя MTK автоматизирует огромный объем работы, он не обеспечивает полный сценарий инициализации, который мы могли бы использовать для настройки Drupal. Во время переноса мы столкнулись с несколькими вопросами:

  • Конфигурация bufferpool и tablespace
  • Целостность Long Object (LOB)
  • Атрибуты таблиц со значениями по умолчанию
  • Инициализация данных по умолчанию

Эти вопросы могут быть решены быстро и просто. Первым шагом, который мы посчитали важным, являлось создание табличных областей (tablespace) bufferpool, tablespace и temporary для базы данных (см. листинг 20).

Листинг 20. Создание табличных областей bufferpool, tablespace и temporary
------------------------------------------------
-- Укажите длину и размер ваших страниц bufferpool 
------------------------------------------------
CREATE BUFFERPOOL "BP_DRPL" IMMEDIATE SIZE 1000 AUTOMATIC PAGESIZE 4K;

CREATE TABLESPACE "TS_DRPL" PAGESIZE 4K BUFFERPOOL "BP_DRPL";

CREATE SYSTEM TEMPORARY TABLESPACE "TMPTS_DRPL" PAGESIZE 4K BUFFERPOOL "BP_DRPL";

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

Листинг 21. Фрагмент для добавления в выражение CREATE TABLE для помещения таблицы в нужную табличную область
IN "TS_DRPL"

Следующий шаг - изменить все LOB на CLOB соответствующего размера. Мы использовали операцию глобального поиска и замены всех наших LOB, как показано в листинге 22.

Листинг 22. Замена LOB на CLOB
CLOB(10M) NOT LOGGED NOT COMPACT

Сюда могут быть добавлены и другие предложения, например, NOT NULL или WITH DEFAULT, в зависимости от определения оригинальной таблицы MySQL.

Третья задача - добавить необходимые предложения WITH DEFAULT в сценарий инициализации базы данных. Это наиболее утомительная часть процесса переноса. Мы шли от одной таблицы к другой, добавляя необходимые предложения значений по умолчанию на основе оригинального сценария инициализации MySQL. Причина этого - интенсивное использование системой Drupal значений по умолчанию в своих запросах; без них Drupal не может функционировать правильно.

Наконец, сценарий инициализации MySQL вставляет много значений по умолчанию во вновь создаваемые таблицы. Мы продублировали это в сценарии инициализации DB2, чтобы он был согласован с механизмом установки Drupal. Вы можете загрузить полный сценарий инициализации.

Создание файла интерфейса к базе данных

Следующий шаг - создание необходимого PHP-кода, взаимодействующего с базой данных. Этот код следует предопределенному интерфейсу функций в includes/database.mysql.inc. Мы начали процесс реализации с копирования полного файла реализации для MySQL в файл includes/database.ibmdb2.inc. Обратите внимание на ibmdb2 в названии файла. Этот маркер используется в качестве идентификатора типа базы данных, который применяется в строке соединения с базой данных, расположенной в файле sites/.../settings.php. Реализация интерфейса к базе данных Drupal с использованием модуля PHP DB2 относительно простая задача, но здесь имеется несколько "капканов", которых нужно избежать.

Реализация db_query_range()
MySQL предоставляет предложения, которые позволяют ограничивать число строк результата, возвращаемых из запроса. Эти строки могут быть из начала, середины или конца возвращенных результатов. DB2 Express-C не имеет аналогичного синтаксического элемента; эта функция должна быть реализована при помощи выражения, приведенного в листинге 23.
Листинг 23. Реализация эквивалента db_query_range
SELECT c1, c2, ... FROM (SELECT ROW_NUMBER() OVER() AS rn, t.* FROM (<original query>) 
       AS X WHERE rn BETWEEN n AND m

Эта функция использует структуру ROW_NUMBER() OVER() для добавления необходимой информации о диапазоне в строки, возвращаемые из оригинального запроса. Ограничение достигается при помощи структуры BETWEEN n AND m, которая является аналогом LIMIT num OFFSET o. В листинге 24 показан релевантный фрагмент кода для функции db_query_range().

Листинг 24. Релевантный код для функции db_query_range
  $query = preg_replace("/SELECT/i", "SELECT O.* FROM 
            (SELECT I.*, ROW_NUMBER() OVER () sys_row_num FROM (SELECT", $query);
  if(!$query) {
    return false;
  }
  
  $last_record = $count + $from;
  $query .= ") AS I) AS O WHERE sys_row_num BETWEEN $from AND $last_record";

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

Реализация db_num_rows()
После прочтения документации по функциям mysql_num_rows() и db2_num_rows() вы заметите, что они используются для решения задач различного рода. DB2-функция больше похожа на mysql_affected_rows(), используемую после запросов UPDATE, INSERT или DELETE. Для того чтобы реализовать функцию Drupal db_num_rows(), мы должны повторно выполнить последний запрос и узнать количество результатов, а не сами результаты. Это процесс, состоящий из двух шагов. Первый шаг требует небольшой модификации функции _db_query() (листинг 25).
Листинг 25. Модификация _db_query() для реализации функции db_num_rows
global $last_query;

if ($result) {
  $last_query = $query;
  return $query
}

Этот код сохраняет последний выполненный запрос в глобальной переменной, для того чтобы его можно было выполнить повторно при вызове db_num_rows(). Второй шаг - посчитать количество возвращаемых строк запросом, сохраненным на первом шаге. Этот шаг показан во фрагменте кода в листинге 26.

Листинг 26. Фрагмент кода для количества строк запроса
return db_result(db_query("SELECT COUNT(*) FROM ($last_query) AS C"));

Эта функция выполняет тот же запрос, но запрашивает только количество найденных строк. Такая реализация не является идеальной, поскольку использует глобальные переменные для сохранения информации между вызовами функции, но это эффективный метод поддержки DB2 Express-C в Drupal без модификации ядра уровня абстракции базы данных в Drupal.

Ссылки на полную информацию о начальной реализации уровня абстракции базы данных в Drupal для IBM DB2 Express-C приведены в разделе "Ресурсы".


Резюме

В данной статье вы исследовали уровень абстракции базы данных в Drupal, который позволяет системе Drupal поддерживать много различных баз данных посредством одного общего API. Вы также узнали о системе разбивки на страницы, позволяющей выполнять навигацию по большим наборам данных в постраничном режиме. Система разбивки на страницы является примером приложения уровня абстракции базы данных. Вы узнали о том, как разрешить системе Drupal использовать IBM DB2 Express-C, бесплатную версию продукта IBM DB2. Вы также узнали о том, как написать переносимый код для базы данных, а также как установить и управлять схемой базы данных вашего модуля от одной версии к другой.

Не пропустите следующую статью данной серии. Вы познакомитесь с нашим определением экстранет, соответствующим требованиям заказчика, и узнаете о приемах реализации, использованных для создания сайта IBC как экстранет Web-сайта.


Загрузка

ОписаниеИмяРазмер
Код ibmdb2i-osource9code.zip9KB

Ресурсы

Научиться

Получить продукты и технологии

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Open source
ArticleID=185566
ArticleTitle=Использование ПО с открытым исходным кодом для создания Web-сайта для совместной работы: Часть 9. Освоение уровня базы данных
publish-date=12252006