ertttert
С помощью уровня абстракции баз данных Drupal поддерживает различные СУБД — MySQL, PostreSQL, SQLite и т.д. Каждый модуль, которому для работы нужна таблица базы данных, описывает эту таблицу для Drupal с помощью определения схемы. Затем Drupal транслирует такое определение в синтаксис, понятный для конкретной СУБД.
Как было сказано в главе 2, при написании модуля, в котором нужно создавать и сохранять одну или несколько таблиц баз данных, инструкции по созданию и обслуживанию табличной структуры заносятся в файл .install
, который распространяется вместе с модулем.
Во время инсталляции нового модуля Drupal автоматически проверяет, имеется ли в файле .install
определение схемы (рис. 5.3). Если имеется, то Drupal создает таблицу (или таблицы) базы данных в этой схеме. Ниже приведен пример общей структуры определения схемы:
$schema['tablename'] =array( // Описание таблицы. 'description' =>t( 'Description of what the table is used for.') ,// Описание, для чего предназначена таблица. 'fields' => array( // Определение поля. 'field1' =>array( 'type' => 'int','unsigned' => TRUE,'not null' => TRUE,'default' => 0,'description' =>t( 'Description of what this field is used for.') ,// Описание, для чего предназначено поле. ) ,) ,// Объявления индексов. 'primary key' =>array( 'field1') ,) ;
Рассмотрим определение схемы для таблицы книг по Drupal, которая находится по адресу modules/book/book.install
:
/** * Реализация hook_schema(). */ function book_schema() { $schema['book'] =array( 'description' => 'Stores book outline information. Uniquely connects each node in the outline to a link in {menu_links}',// Хранит краткие описания книг. Уникально сочетает каждую ноду // в кратких описаниях со ссылкой в {menu_links} 'fields' =>array( 'mlid' =>array( 'type' => 'int','unsigned' => TRUE,'not null' => TRUE,'default' => 0,'description' => "The book page's {menu_links}.mlid.",// Идентификатор ссылки меню для страницы книги ) ,'nid' =>array( 'type' => 'int','unsigned' => TRUE,'not null' => TRUE,'default' => 0,'description' => "The book page's {node}.nid.",// Идентификатор ноды для страницы книги ) ,'bid' =>array( 'type' => 'int','unsigned' => TRUE,'not null' => TRUE,'default' => 0,'description' => "The book ID is the {book}.nid of the top-level page.",// Идентификатор книги — это идентификатор ноды страницы верхнего уровня. ) ,) ,'primary key' =>array( 'mlid') ,'unique keys' =>array( 'nid' =>array( 'nid') ,) ,'indexes' =>array( 'bid' =>array( 'bid') ,) ,) ;return $schema; }
Это определение схемы описывает таблицу book
с тремя полями типа int
. В нем также указаны первичный ключ, уникальный индекс (т.е. все значения в данном поле уникальны) и обычный индекс. Обратите внимание, что когда описание поля ссылается на поле из другой таблицы, используются фигурные скобки. Это позволяет модулю схемы (см. следующий раздел) создать удобные гиперссылки на описания таблиц.
Вот тут вы можете подумать: “Ничего себе! Создание таких больших массивов для описания в Drupal всех моих таблиц — это жуткая рутина!” Не пугайтесь. Просто загрузите модуль схемы из http://drupal.org/project/schema и активируйте его для своего сайта. Выберите пункт меню → (Структура→Схема) и перейдите на вкладку (Просмотр) — это позволит увидеть определение схемы для любой таблицы базы данных. Так что если вы создали таблицу с помощью SQL, вы сможете, воспользовавшись модулем схемы, получить для нее определение схемы, а затем скопировать и вставить его в файл .install
.
Модуль схемы позволяет также просмотреть схему любого модуля. Например, на рис. 5.4 показано представление модуля схемы для книг. Обратите внимание на то, как имена таблиц, заключенные в фигурные скобки в описаниях таблиц и полей, превращаются в удобные ссылки.
Тип поля, объявленный в определении схемы, отображается на внутренний тип поля в СУБД. Например, целочисленное поле с объявленным размером tiny
становится полем TINYINT
в MySQL или полем small int
в PostgreSQL. Действительное отображение можно просмотреть, отобразив результаты функции getFieldTypeMap()
, или обратившись к табл. 5.1 далее в главе.
Текстовые поля содержат текст.
Поля символов переменной длины — наиболее часто применяемый тип поля для хранения текста длиной до 256 символов. Максимальное количество символов задается в ключе length
. Длина поля varchar
может быть 0–255 символов в MySQL 5.0.2 и более старых версиях, и 0–65535 в MySQL 5.0.3 и более новых версиях. Длины полей varchar
в PostgreSQL могут быть еще больше.
$field['fieldname'] =array( 'type' => 'varchar', // Обязательно. 'length' => 255, // Обязательно. 'not null' => TRUE, // По умолчанию FALSE. 'default' => 'chocolate', // См. ниже. 'description' => t( 'Always state the purpose of your field.') ,// Всегда описывайте назначение поля. ) ;
Если ключ default
не задан, а ключ not null
установлен в FALSE, то в качестве значения по умолчанию принимается NULL.
Поля типа char
являются символьными полями фиксированной длины. Количество символов определяется ключом length
. Длины полей char
в MySQL могут быть от 0 до 255 символов.
$field['fieldname'] =array( 'type' => 'char',// Обязательно. 'length' => 64,// Обязательно. 'not null' => TRUE,// По умолчанию FALSE. 'default' => 'strawberry',// См. ниже. 'description' =>t( 'Always state the purpose of your field.') ,) ;
Если ключ default
не задан, а ключ not null
установлен в FALSE, то в качестве значения по умолчанию принимается NULL.
Поля типа text
используются для текстовых данных, которые могут иметь большой размер. Например, поле body
из таблицы node_revisions
(где хранится текст тела ноды) — как раз такого типа. Для полей типа text
значения по умолчанию не могут использоваться.
$field['fieldname'] =array( 'type' => 'text',// Обязательно. 'size' => 'small',// tiny | small | normal | medium | big 'not null' => TRUE,// По умолчанию FALSE. 'description' =>t( 'Always state the purpose of your field.') ,) ;
Числовые типы данных используются для хранения чисел и могут быть integer
, serial
, float
и numeric
.
Этот тип поля используется для хранения целых чисел, таки как идентификаторы нод. Если ключ unsigned
установлен в TRUE, то отрицательные значения не допускаются.
$field['fieldname'] =array( 'type' => 'int',// Обязательно. 'unsigned' => TRUE,// По умолчанию FALSE. 'size' => 'small',// tiny | small | medium | normal | big 'not null' => TRUE,// По умолчанию FALSE. 'description' =>t( 'Always state the purpose of your field.') ,) ;
Поле типа serial
хранит автоинкрементные числа. Например, при добавлении ноды значение поля nid
в таблице node
увеличивается на 1. Для этого нужно вставить строку и вызвать функцию db_last_insert_id()
. Если строка добавлена в другом потоке между вставкой строки и выборкой последнего идентификатора, то все равно возвращается корректный идентификатор, поскольку он отслеживается для каждого подключения отдельно. Автоинкрементные поля должны быть индексированными; обычно они служат первичными ключами.
$field['fieldname'] =array( 'type' => 'serial',// Обязательно. 'unsigned' => TRUE,// По умолчанию FALSE. Серийные числа обычно положительны. 'size' => 'small',// tiny | small | medium | normal | big 'not null' => TRUE,// По умолчанию FALSE. Обычно TRUE // для автоинкрементных полей. 'description' =>t( 'Always state the purpose of your field.') ,) ;
Числа с плавающей точкой хранятся в типе данных float
. Обычно нет особой разницы между числами размеров tiny
, small
, medium
и normal
; размер big
означает поле с двойной точностью.
$field['fieldname'] =array( 'type' => 'float',// Обязательно. 'unsigned' => TRUE,// По умолчанию FALSE. 'size' => 'normal',// tiny | small | medium | normal | big 'not null' => TRUE,// По умолчанию FALSE. 'description' =>t(' Always state the purpose of your field.') ,) ;
Тип numeric
позволяет задавать точность и масштаб чисел. Точность — это общее количество значащих цифр в числе, а масштаб — общее количество цифр справа от десятичной точки. Например, у числа 123.45 точность 5 и масштаб 2. Ключ size
не используется. На момент написания этих строк поля numeric
в схеме ядра Drupal не использовались.
$field['fieldname'] =array( 'type' => 'numeric',// Обязательно. 'unsigned' => TRUE,// По умолчанию FALSE. 'precision' => 5,// Значащие цифры. 'scale' => 2,// Цифры справа от десятичной точки. 'not null' => TRUE,// По умолчанию FALSE. 'description' =>t( 'Always state the purpose of your field.') ,) ;
Этот тип данных не используется в ядре Drupal, вместо него применяются метки времени Unix в целочисленных полях. Формат datetime
является составным: он содержит одновременно дату и время.
$field['fieldname'] =array( 'type' => 'datetime',// Обязательно. 'not null' => TRUE,// По умолчанию FALSE. 'description' =>t( 'Always state the purpose of your field.') ,) ;
Тип данных больших двоичных объектов (binary large object data — blob
) применяется для хранения двоичных данных (например, таблица кэша Drupal используется для хранения кэшированных данных). Двоичные данные могут содержать музыку, изображения или видео. Доступны два размера: normal
(нормальный) и big
(большой).
$field['fieldname'] =array( 'type' => 'blob',// Обязательно. 'size' => 'normal'// normal | big 'not null' => TRUE,// По умолчанию FALSE. 'description' =>t( 'Always state the purpose of your field.') ,) ;
Если тип столбца в используемой СУБД в точности известен, то в определении схемы можно установить ключ mysql_type
(или pgsql_type). Он переопределяет ключи типа и размера для этой СУБД. Например, в MySQL имеется тип поля TINYBLOB
для небольших двоичных объектов. Чтобы указать, что среда Drupal должна использовать TINYBLOB
при работе с MySQL, но вернуться к обычному типу BLOB
в случае другой СУБД, поле понадобится определить следующим образом:
$field['fieldname'] =array( 'mysql_type' => 'TINYBLOB',// Для использования с MySQL. 'type' => 'blob',// Для других СУБД. 'size' => 'normal',// Для других СУБД. 'not null' => TRUE,'description' =>t( 'Wee little blobs.') ) ;
Встроенные типы MySQL и PostgreSQL приведены в табл. 5.1.
Таблица 5.1. Отображение ключей type и size в определениях схемы на типы конкретных СУБД
varchar | normal | VARCHAR | varchar | VARCHAR |
char | normal | CHAR | character | VARCHAR |
text | tiny | TINYTEXT | text | TEXT |
text | small | TINYTEXT | text | TEXT |
text | medium | MEDIUMTEXT | text | TEXT |
text | big | LONGTEXT | text | TEXT |
text | normal | TEXT | text | TEXT |
serial | tiny | TINYINT | serial | INTEGER |
serial | small | SMALLINT | serial | INTEGER |
serial | medium | MEDIUMINT | serial | INTEGER |
serial | big | BIGINT | bigserial | INTEGER |
serial | normal | INT | serial | INTEGER |
int | tiny | TINYINT | smallint | INTEGER |
int | small | SMALLINT | smallint | INTEGER |
int | medium | MEDIUMINT | int | INTEGER |
int | big | BIGINT | bigint | INTEGER |
int | normal | INT | int | INTEGER |
float | tiny | FLOAT | real | FLOAT |
float | small | FLOAT | real | FLOAT |
float | medium | FLOAT | real | FLOAT |
float | big | DOUBLE | double precision | FLOAT |
float | normal | FLOAT | real | FLOAT |
numeric | normal | DECIMAL | numeric | NUMERIC |
blob | big | LONGBLOB | bytea | BLOB |
blob | normal | BLOB | bytea | BLOB |
datetime | normal | DATETIME | timestamp | TIMESTAMP |
При создании новой версии модуля иногда требуется изменить схему базы данных. Возможно, необходимо добавить столбец или индекс для столбца. Просто взять и создать новую таблицу нельзя, т.к. она содержит данные. Вот так можно изменить базу без ущерба для данных.
hook_schema()
в файле .install
, чтобы у новых пользователей, которые будут инсталлировать модуль, устанавливалась новая схема. Определение схемы в файле .install
всегда будет самой свежей схемой для таблиц и полей модуля.modulename_update_7000()
, а вторая — modulename_update_7001()
. Ниже приведен пример из файла modules/comment/comment.install
, где таблица, используемая для хранения комментариев, переименована с comments в comment:
/** * Переименование таблицы {comments} в {comment}. */ function comment_update_7002() {db_rename_table( 'comments', 'comment') ; }
http://example.com/update.php
после обновления модуля.Полный список функций для работы со схемами приведен на странице http://api.drupal.org/api/group/schemaapi/7.
system
. После выполнения обновления, приведенного в данном разделе, в строке для модуля комментария будет содержаться значение schema_ version
, равное 7002. Чтобы Drupal отбросила это значение, используйте параметр Reinstall Modules
в модуле Devel
или удалите строку модуля из таблицы system
.При отключении модуля все данные, сохраненные этим модулем в базе данных, остаются без изменений, на случай, если администратор передумает и снова активирует модуль. На странице
(Модули) имеется вкладка (Деинсталляция), которая автоматически удаляет данные из базы. Может понадобиться удалить все переменные, определенные в то же время. Вот пример для модуля аннотирования, который был написан в главе 2:/** * Реализация hook_uninstall(). */ function annotate_uninstall() {// Очистка записи в таблице переменных. variable_del( 'annotate_nodetypes') ; }
Обычно модули сами создают и используют свои таблицы. Но что если модулю надо изменить существующую таблицу? Допустим, модулю абсолютно необходимо добавить столбец в таблицу node
. Конечно, проще всего взять базу данных и добавить нужный столбец. Но тогда перестанут быть актуальными определения схемы Drupal, которые должны соответствовать реальной таблице базы данных. Существует лучший способ: hook_schema_alter()
. Предположим, что имеется модуль, который каким-нибудь образом помечает ноды, и по соображениям производительности нужно обязательно использовать существующую таблицу node
, а не собственную таблицу, соединенную с идентификаторами нод. Модуль должен сделать две вещи: изменить таблицу node
при инсталляции модуля и изменить схему, чтобы она соответствовала структуре базы данных. Первый пункт выполняется с помощью функции hook_install()
, а второй — с помощью hook_schema_ alter()
. Если модуль называется markednode.module
, то файл markednode.install
будет содержать следующие инструкции:
/** * Реализация hook_install(). */ function markednode_install() { $field =array( 'type' => 'int','unsigned' => TRUE,'not null' => TRUE,'default' => 0,'initial' => 0,// Задает начальное значение для существовавших ранее нод. 'description' =>t( 'Whether the node has been marked by the markednode module.') ,// Помечена ли нода модулем markednode ) ;// Создание обычного индекса 'marked' по полю 'marked'. $keys['indexes'] =array( 'marked' =>array( 'marked') ) ;db_add_field( 'node', 'marked', $field, $keys) ; }/** * Реализация hook_schema_alter(). Содержимое $schema изменяется по ссылке. * * @param $schema * Схема для всей системы, собранная drupal_get_schema(). */ function markednode_schema_alter( &$schema) {// Добавление поля в существующую схему. $schema['node']['fields']['marked'] =array( 'type' => 'int','unsigned' => TRUE,'not null' => TRUE,'default' => 0,'description' =>t( 'Whether the node has been marked by the markednode module.') ,// Помечена ли нода модулем markednode ) ; }
Всего комментариев: 0 | |