Commit a243e821 authored by Dries's avatar Dries
Browse files

- Pactch #569224 by bangpound: expose field storage details through field attach.

parent 7a9fc8a3
......@@ -1140,6 +1140,47 @@ function hook_field_storage_info_alter(&$info) {
);
}
/**
* Reveal the internal details about the storage for a field.
*
* For example, an SQL storage module might return the Schema API structure for
* the table. A key/value storage module might return the server name,
* authentication credentials, and bin name.
*
* Field storage modules are not obligated to implement this hook. Modules
* that rely on these details must only use them for read operations.
*
* @param $field
* A field structure.
* @param $instance
* A field instance structure.
* @return
* An array of details.
* - The first dimension is a store type (sql, solr, etc).
* - The second dimension indicates the age of the values in the store
* FIELD_LOAD_CURRENT or FIELD_LOAD_REVISION.
* - Other dimensions are specific to the field storage module.
*/
function hook_field_storage_details($field, $instance) {
}
/**
* Perform alterations on Field API storage details.
*
* The storage details are appended to the field instance structure after this
* hook is invoked. Read and alter the $details only.
*
* @param $details
* An array of storage details for fields as exposed by
* hook_field_storage_details() implementations.
* @param $field
* A field structure.
* @param $instance
* A field instance structure.
*/
function hook_field_storage_details_alter(&$details, $field, $instance) {
}
/**
* Load field data for a set of objects.
*
......
......@@ -243,6 +243,11 @@ function _field_info_collate_fields($reset = FALSE) {
// are thus not in $definitions['instances'].
$info['fields'][$instance['field_name']]['bundles'][] = $instance['bundle'];
$info['field_ids'][$instance['field_id']]['bundles'][] = $instance['bundle'];
// Add storage details.
$details = (array) module_invoke($field['storage']['module'], 'field_storage_details', $field, $instance);
drupal_alter('field_storage_details', $details, $field, $instance);
$info['instances'][$instance['bundle']][$instance['field_name']]['storage_details'] = $details;
}
}
......
......@@ -273,6 +273,47 @@ class FieldAttachStorageTestCase extends FieldAttachTestCase {
}
}
/**
* Test storage details alteration.
*
* @see field_test_storage_details_alter()
*/
function testFieldStorageDetailsAlter() {
$field_name = 'field_test_change_my_details';
$field = array(
'field_name' => $field_name,
'type' => 'test_field',
'cardinality' => 4,
'storage' => array('type' => 'field_test_storage'),
);
$field = field_create_field($field);
$instance = array(
'field_name' => $field_name,
'bundle' => 'test_bundle',
);
field_create_instance($instance);
$field = field_info_field($instance['field_name']);
$instance = field_info_instance($instance['field_name'], $instance['bundle']);
// The storage details are indexed by a storage engine type.
$this->assertTrue(array_key_exists('drupal_variables', $instance['storage_details']), t('The storage type is Drupal variables.'));
$details = $instance['storage_details']['drupal_variables'];
// The field_test storage details are indexed by variable name. The details
// are altered, so moon and mars are correct for this test.
$this->assertTrue(array_key_exists('moon', $details[FIELD_LOAD_CURRENT]), t('Moon is available in the instance array.'));
$this->assertTrue(array_key_exists('mars', $details[FIELD_LOAD_REVISION]), t('Mars is available in the instance array.'));
// Test current and revision storage details together because the columns
// are the same.
foreach ((array) $field['columns'] as $column_name => $attributes) {
$this->assertEqual($details[FIELD_LOAD_CURRENT]['moon'][$column_name], $column_name, t('Column name %value matches the definition in %bin.', array('%value' => $column_name, '%bin' => 'moon[FIELD_LOAD_CURRENT]')));
$this->assertEqual($details[FIELD_LOAD_REVISION]['mars'][$column_name], $column_name, t('Column name %value matches the definition in %bin.', array('%value' => $column_name, '%bin' => 'mars[FIELD_LOAD_REVISION]')));
}
}
/**
* Tests insert and update with missing or NULL fields.
*/
......
......@@ -658,3 +658,25 @@ function field_sql_storage_field_storage_purge_field($field) {
db_drop_table($revision_name);
}
/**
* Implement hook_field_storage_details().
*/
function field_sql_storage_field_storage_details($field, $instance) {
$details = array();
// Add field columns.
foreach ((array) $field['columns'] as $column_name => $attributes) {
$real_name = _field_sql_storage_columnname($field['field_name'], $column_name);
$columns[$column_name] = $real_name;
}
return array(
'sql' => array(
FIELD_LOAD_CURRENT => array(
_field_sql_storage_tablename($field) => $columns,
),
FIELD_LOAD_REVISION => array(
_field_sql_storage_revision_tablename($field) => $columns,
),
),
);
}
......@@ -369,6 +369,34 @@ class FieldSqlStorageTestCase extends DrupalWebTestCase {
$this->assertEqual($entity->{$field_name}[FIELD_LANGUAGE_NONE][0]['value'], 'field data', t("Index changes performed without dropping the tables"));
}
}
/**
* Test the storage details.
*/
function testFieldStorageDetails() {
$current = _field_sql_storage_tablename($this->field);
$revision = _field_sql_storage_revision_tablename($this->field);
// Retrieve the field and instance with field_info so the storage details are attached.
$field = field_info_field($this->field['field_name']);
$instance = field_info_instance($this->instance['field_name'], $this->instance['bundle']);
// The storage details are indexed by a storage engine type.
$this->assertTrue(array_key_exists('sql', $instance['storage_details']), t('The storage type is SQL.'));
// The SQL details are indexed by table name.
$details = $instance['storage_details']['sql'];
$this->assertTrue(array_key_exists($current, $details[FIELD_LOAD_CURRENT]), t('Table name is available in the instance array.'));
$this->assertTrue(array_key_exists($revision, $details[FIELD_LOAD_REVISION]), t('Revision table name is available in the instance array.'));
// Test current and revision storage details together because the columns
// are the same.
foreach ((array) $this->field['columns'] as $column_name => $attributes) {
$storage_column_name = _field_sql_storage_columnname($this->field['field_name'], $column_name);
$this->assertEqual($details[FIELD_LOAD_CURRENT][$current][$column_name], $storage_column_name, t('Column name %value matches the definition in %bin.', array('%value' => $column_name, '%bin' => $current)));
$this->assertEqual($details[FIELD_LOAD_REVISION][$revision][$column_name], $storage_column_name, t('Column name %value matches the definition in %bin.', array('%value' => $column_name, '%bin' => $revision)));
}
}
function getIndexes($table) {
$indexes = array();
......
......@@ -666,6 +666,49 @@ function field_test_field_storage_info() {
);
}
/**
* Implement hook_field_storage_details().
*/
function field_test_field_storage_details($field, $instance) {
$details = array();
// Add field columns.
$columns = array();
foreach ((array) $field['columns'] as $column_name => $attributes) {
$columns[$column_name] = $column_name;
}
return array(
'drupal_variables' => array(
'field_test_storage_data[FIELD_LOAD_CURRENT]' => $columns,
'field_test_storage_data[FIELD_LOAD_REVISION]' => $columns,
),
);
}
/**
* Implement hook_field_storage_details_alter().
*
* @see FieldAttachStorageTestCase::testFieldStorageDetailsAlter()
*/
function field_test_field_storage_details_alter(&$details, $field, $instance) {
// For testing, storage details are changed only because of the field name.
if ($field['field_name'] == 'field_test_change_my_details') {
$columns = array();
foreach ((array) $field['columns'] as $column_name => $attributes) {
$columns[$column_name] = $column_name;
}
$details['drupal_variables'] = array(
FIELD_LOAD_CURRENT => array(
'moon' => $columns,
),
FIELD_LOAD_REVISION => array(
'mars' => $columns,
),
);
}
}
/**
* Helper function: store or retrieve data from the 'storage backend'.
*/
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment