Newer
Older
/**
* @file
* Hooks and API functions for data module.
*/
/**
* Implementation of hook_views_api().
*/
function data_views_api() {
return array(
'api' => '2.0',
);
/**
* Implementation of hook_schema_alter().
*
* This is a central piece of data module:
* Here we tack schema information that has been defined through the API in data_tables
* or by hook_data_default onto the $schema array.
* We do not use hook_schema() for exposing schema information as this would cause a race
* condition: ctools/exports looks for data module's data_tables at the same time when
* we are actually rebuilding it - follow path through
* data_get_all_tables() ... _data_load_table() ... ctools_export_load_object().
*/
function data_schema_alter(&$schema) {
Alex Barth
committed
$tables = data_get_all_tables(TRUE);
foreach ($tables as $table) {
// Only add table if not yet present or the table at hand is defined in DB.
// This allows other modules to "own" data managed tables which in turn makes Drupal
Alex Barth
committed
// track schema versions - the prerequisit for using hook_update_N() on data tables.
if (!isset($schema[$table->get('name')]) || (EXPORT_IN_DATABASE & $table->get('export_type'))) {
$schema[$table->get('name')] = $table->get('table_schema');
}
}
}
* Create a table.
* @see DataTable class.
* String that identifies the data table. It is recommended to use
* data_name() to generate a table name in the data namespace. For
* example: $table = data_get_tabe(data_name('my_table'));
* @param $schema
* Schema for the table.
* @param $title
* A natural title for the table.
Alex Barth
committed
* A DataTable object if one could be created, FALSE otherwise.
function data_create_table($name, $schema, $title = NULL) {
Alex Barth
committed
$table = DataTable::instance($name);
if ($table->create($schema)) {
if (!empty($title)) {
$table->update(array('title' => $title));
}
return $table;
Alex Barth
committed
return FALSE;
* @see DataTable class.
* @param $name
* Unique name of the table.
Alex Barth
committed
* A unique DataTable object if defined, FALSE otherwise.
*
* Note: In some circumstances, a table may be defined while it does not exist
Alex Barth
committed
* in the database. In these cases, data_get_table() would still return a valid
* DataTable object.
Alex Barth
committed
$table = DataTable::instance($name);
if ($table->defined()) {
Alex Barth
committed
* @deprecated - use $table->drop() instead.
* @todo: remove.
*/
function data_drop_table($name) {
if ($table = data_get_table($name)) {
$table->drop();
}
}
function data_get_all_tables($reset = FALSE) {
if ($tables = _data_load_table(NULL, $reset)) {
foreach ($tables as $table_name => $table) {
if ($table = data_get_table($table_name)) {
$tables[$table_name] = $table;
}
/**
* Get Data handler for a table.
* @see class DataHandler
* @param $table_name
* String that is the name of a table.
* DataHandler object that provides access to a table's data.
*/
function data_get_handler($table_name) {
return DataHandler::instance($table_name);
}
* Get a list of supported field definitions.
*
* This list is a sub set of Schema API data types
* http://drupal.org/node/159605
* The keys are simplified handles.
*/
function data_get_field_definitions() {
return array(
'int' => array(
'type' => 'int',
'not null' => FALSE,
),
'unsigned int' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => FALSE,
),
'serial' => array(
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
),
'varchar' => array(
'type' => 'varchar',
'length' => 255,
'not null' => FALSE,
),
'text' => array(
'type' => 'text',
'not null' => FALSE,
),
'bigtext' => array(
'type' => 'text',
'not null' => FALSE,
'size' => 'big',
),
'float' => array(
'type' => 'float',
'size' => 'medium',
'not null' => FALSE,
),
'double' => array(
'type' => 'float',
'size' => 'big',
'not null' => FALSE,
),
'geometry' => array(
'type' => 'geometry',
'mysql_type' => 'geometry',
'pgsql_type' => 'geometry',
),
* Get a definition key into a schema API type definition.
* If no type can be found, FALSE will be returned.
function data_get_field_definition($key) {
$definitions = data_get_field_definitions();
if (isset($definitions[$key])) {
return $definitions[$key];
/**
* Get schema API field types supported by Data module.
*/
function data_get_field_types() {
$definitions = data_get_field_definitions();
$types = array();
foreach ($definitions as $def) {
$types[$def['type']] = $def['type'];
}
return $types;
}
/**
* Get schema API field sizes.
*/
function data_get_field_sizes() {
$sizes = array('normal', 'tiny', 'small', 'medium', 'big');
return drupal_map_assoc($sizes);
}
/**
* Get a Schema API PK definition for a given field type.
*/
function data_get_pk_definition($field_name, $spec) {
if ($spec['type'] == 'text') {
return array($field_name, 255);
return $field_name;
}
}
/**
* Get a Schema API index definition for a given field type.
* @todo: support multiple name/type combinations.
*/
function data_get_index_definition($field_name, $spec) {
// Default to 255 for now.
if ($spec['type'] == 'text') {
// @todo: what's the right format here? this is broken.
return array(array($field_name, 255));
return array($field_name);
/**
* Create a table name in the data namespace.
* @todo: make overridable.
*/
function data_name($table) {
return 'data_table_'. $table;
}
/**
* Create a safe name for MySQL field or table names.
* - make sure all unsafe characters are removed.
* - filter magic words.
* - test pgsql.
*/
function data_safe_name($name) {
$map = array(
'.' => '_',
':' => '',
'/' => '',
'-' => '_',
' ' => '_',
',' => '_',
);
$simple = trim(strtolower(strip_tags($name)));
// Limit length to 64 as per http://dev.mysql.com/doc/refman/5.0/en/identifiers.html
$simple = substr(strtr($simple, $map), 0, 64);
if (is_numeric($simple)) {
// We need to escape numerics because Drupal's drupal_write_record()
// does not properly escape token MYSQL names.
$simple = '__num_'. $simple;
}
return db_escape_table($simple);
}
/**
* Helper function to create a natural name.
* underscored_name -> Underscored name
*/
function data_natural_name($name) {
return ucfirst(strtolower(str_replace('_', ' ', $name)));
}
/**
* Helper function to generate a schema.
* Example:
* $table->create(data_build_schema($keys));
* @todo: check for table name collisions
* @todo: add type detection
* @todo: add meta info handling
* @todo: add primary key handling
* @todo: may be add option to add a full fledged schema here?
*/
function data_build_schema($keys) {
// Build the table definition.
// Fall back to varchar if no valid type is given.
$fields = $schema = array();
foreach ($keys as $k => $key) {
if ($definition = data_get_field_definition($key)) {
$fields[data_safe_name($k)] = $definition;
$fields[data_safe_name($k)] = data_get_field_definition('varchar');
$schema['fields'] = $fields;
$schema['indexes'] = array();
return $schema;
}
/**
* Build a full schema api field definition.
* @param $stub
* Array with at least one key 'type'.
*/
function data_build_field_definition($stub) {
$spec = array();
$spec['type'] = $stub['type'];
$spec['size'] = empty($stub['size']) ? 'normal' : $stub['size'];
if ($spec['type'] == 'int') {
$spec['unsigned'] = empty($stub['unsigned']) ? FALSE : TRUE;
}
if ($spec['type'] == 'varchar') {
$spec['length'] = 255;
unset($spec['size']);
if ($spec['type'] == 'geometry') {
$spec['mysql_type'] = 'geometry';
$spec['pgsql_type'] = 'GEOMETRY';
}
* Export a data table. This does not export the content of a table - only its schema
* and any meta information (title, name, meta...).
* @param $name
* The name of the table to be exported.
*
* @return
* Exportable code.
*
* Only available if ctools is installed.
*/
function data_export($name, $indent = '') {
ctools_include('export');
$result = ctools_export_load_object('data_tables', 'names', array($name));
if (isset($result[$name])) {
return ctools_export_object('data_tables', $result[$name], $indent);
Alex Barth
committed
* Loads data table info from the database.
*/
function _data_load_table($name = NULL, $reset = FALSE) {
Alex Barth
committed
ctools_include('export');
if ($reset) {
ctools_static_reset('ctools_export_load_object');
ctools_static_reset('ctools_export_load_object_all');
if ($name === NULL) {
Alex Barth
committed
return ctools_export_load_object('data_tables', 'all', array());
Alex Barth
committed
else {
$tables = ctools_export_load_object('data_tables', 'names', array($name));
if (isset($tables[$name])) {
return $tables[$name];
}
return FALSE;
}
return FALSE;
}
/**
* Starts overriding a data table by copying it from the default definition into the DB.
* This function does not have any effect if called on a table that does already exist in
* data_tables.
*/
function _data_override($name) {
if (!db_result(db_query("SELECT name FROM {data_tables} WHERE name = '%s'", $name))) {
if ($table = _data_load_table($name)) {
drupal_write_record('data_tables', $table);
}
}
}
if (!isset($included[$class])) {
include drupal_get_path('module', 'data') .'/includes/'. $class .'.inc';
$included[$class] = TRUE;
Alex Barth
committed
/**
* Base class for any exceptions thrown in Data.
*/
class DataException extends Exception {}