data.module in Data 8
Same filename and directory in other branches
Hooks and API functions for data module.
File
data.moduleView source
<?php
/**
* @file
* Hooks and API functions for data module.
*/
use Drupal\Core\Database\Database;
/**
* Load all data tables.
*
* @return array
* Array of TableConfigInterface objects.
*/
function data_get_all_tables($reset = FALSE) {
$storage = \Drupal::entityTypeManager()
->getStorage('data_table_config');
if ($reset) {
$storage
->resetCache();
}
return $storage
->loadMultiple();
}
/**
* Create a table.
*
* @see DataTable class.
*
* @param $name
* 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.
*
* @return \Drupal\data\Entity\TableConfigInterface
* A DataTable object if one could be created, FALSE otherwise.
*/
function data_create_table($name, $schema, $title = NULL) {
$storage = \Drupal::entityTypeManager()
->getStorage('data_table_config');
/** @var \Drupal\data\Entity\TableConfigInterface $table */
$table = $storage
->load($name);
if (!$table || !$table
->exists()) {
$table = $storage
->create(array(
'id' => $name,
'table_schema' => $schema,
));
$table
->save();
}
if ($title) {
$table->title = $title;
$table
->save();
}
return $table;
}
/**
* Get a table if it exists.
*
* @param string $name
* Unique name of the table.
*
* @return \Drupal\data\Entity\TableConfigInterface
* TableConfig entity, or FALSE in case of failure.
*
* Note: In some circumstances, a table may be defined while it does not exist
* in the database. In these cases, data_get_table() would still return a valid
* DataTable object.
*/
function data_get_table($name) {
$table = \Drupal::entityTypeManager()
->getStorage('data_table_config')
->load($name);
if ($table && $table
->defined()) {
return $table;
}
return FALSE;
}
/**
* 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];
}
return FALSE;
}
/**
* 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 array_combine($sizes, $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,
);
}
else {
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,
),
);
}
else {
return array(
$field_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() {
$built_in = 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',
),
);
\Drupal::moduleHandler()
->alter('data_field_definitions', $built_in);
return $built_in;
}
/**
* 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.
*
* @todo: IMPROVE.
*
* - 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 Database::getConnection()
->escapeTable($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;
}
else {
$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';
}
return $spec;
}
/**
* 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.
*/
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);
}
}
/**
* Loads data table info from the database and from CTools exportables.
*
* @param $name
* The name of a table to load. If NULL or omitted, all tables are loaded.
* @param $reset
* Whether to reset CTools' static cache.
*/
function _data_load_table($name = NULL, $reset = FALSE) {
// @todo: implement this.
return FALSE;
ctools_include('export');
if ($reset) {
drupal_static_reset('ctools_export_load_object');
drupal_static_reset('ctools_export_load_object_all');
}
if ($name === NULL) {
return ctools_export_load_object('data_tables', 'all', array());
}
else {
$tables = ctools_export_load_object('data_tables', 'names', array(
$name,
));
if (isset($tables[$name])) {
return $tables[$name];
}
return FALSE;
}
return FALSE;
}
/**
* Helper function for adjusting a table's real schema.
* @todo: this should live in schema module and should use better defined $reason keys.
*
* @throws DataException on error.
*/
function data_alter_table($table, $field_reason) {
list($field, $reason) = explode(': ', $field_reason);
$schema = $table
->get('table_schema');
switch ($reason) {
case 'not in database':
if (isset($schema['fields'][$field])) {
$table
->addField($field, $schema['fields'][$field]);
}
break;
case 'missing in database':
list($type, $field) = explode(' ', $field);
// @todo: support multiple keys.
if ($type == 'indexes') {
$table
->addIndex($field);
}
elseif ($type == 'unique keys') {
$table
->addUniqueKey($field);
}
elseif ($type == 'primary key') {
$table
->addPrimaryKey($schema['primary keys']);
}
break;
case 'primary key:<br />declared':
// @todo: yikes!
$table
->dropPrimaryKey();
$table
->changePrimaryKey($schema['primary keys']);
case 'missing in schema':
if ($field == 'primary key') {
$table
->dropPrimaryKey();
}
break;
case 'unexpected column in database':
$table
->dropField($field);
break;
}
}
/**
* 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 (!\Drupal::database()
->query("SELECT name FROM {data_tables} WHERE name = :name", array(
':name' => $name,
))
->fetchField()) {
if ($table = _data_load_table($name)) {
drupal_write_record('data_tables', $table);
}
}
}
/**
* Implements hook_date_views_fields().
*
* All modules that create custom fields that use the
* 'views_handler_field_date' handler can provide
* additional information here about the type of
* date they create so the date can be used by
* the Date API views date argument and date filter.
*
* @todo: remove the above comment when this hook is properly documented in
* Date module: https://drupal.org/node/2171345
*
* For fields to be considered by Date's compound filter and argument handlers,
* they must have the 'is date' property set. This is taken care of by our
* hook_views_data(), via data_get_table_field_views_data().
*/
function data_date_views_fields($field) {
// $field is of the form "TABLE.FIELD".
list($table_name, $field_name) = explode('.', $field);
$tables = data_get_all_tables();
// If this is being called for a field that's not on one of our data tables,
// then we have nothing to say.
if (!isset($tables[$table_name])) {
return;
}
$table = $tables[$table_name];
$meta = $table
->get('meta');
// We require the field to be configured for its date properties.
// See data_ui_date_form().
if (!isset($meta['fields'][$field_name]['date'])) {
return;
}
// Default values; cribbed from date_views_date_views_fields().
$values = array(
// The type of date: DATE_UNIX, DATE_ISO, DATE_DATETIME.
'sql_type' => DATE_UNIX,
// Timezone handling options: 'none', 'site', 'date', 'utc' .
'tz_handling' => 'site',
// Needed only for dates that use 'date' tz_handling.
'timezone_field' => '',
// Needed only for dates that use 'date' tz_handling.
'offset_field' => '',
// Array of "table.field" values for related fields that should be
// loaded automatically in the Views SQL.
'related_fields' => array(),
// Granularity of this date field's db data.
'granularity' => array(
'year',
'month',
'day',
'hour',
'minute',
'second',
),
);
// Override any properties that may have been set in the table metadata.
foreach (array_keys($values) as $property) {
// The use of '' as the empty value in the form select elements in
// data_ui_date_form() means we can use empty() here.
if (!empty($meta['fields'][$field_name]['date'][$property])) {
$values[$property] = $meta['fields'][$field_name]['date'][$property];
}
}
return $values;
}
Functions
Name | Description |
---|---|
data_alter_table | Helper function for adjusting a table's real schema. @todo: this should live in schema module and should use better defined $reason keys. |
data_build_field_definition | Build a full schema api field definition. |
data_build_schema | Helper function to generate a schema. |
data_create_table | Create a table. |
data_date_views_fields | Implements hook_date_views_fields(). |
data_export | Export a data table. This does not export the content of a table - only its schema and any meta information (title, name, meta...). |
data_get_all_tables | Load all data tables. |
data_get_field_definition | Get a definition key into a schema API type definition. |
data_get_field_definitions | Get a list of supported field definitions. |
data_get_field_sizes | Get schema API field sizes. |
data_get_field_types | Get schema API field types supported by Data module. |
data_get_index_definition | Get a Schema API index definition for a given field type. @todo: support multiple name/type combinations. |
data_get_pk_definition | Get a Schema API PK definition for a given field type. |
data_get_table | Get a table if it exists. |
data_name | Create a table name in the data namespace. @todo: make overridable. |
data_natural_name | Helper function to create a natural name. underscored_name -> Underscored name |
data_safe_name | Create a safe name for MySQL field or table names. |
_data_load_table | Loads data table info from the database and from CTools exportables. |
_data_override | 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. |