field_collection.install in Field collection 7
Same filename and directory in other branches
Install, update and uninstall functions for the field_collection module.
File
field_collection.installView source
<?php
/**
* @file
* Install, update and uninstall functions for the field_collection module.
*/
/**
* Implements hook_schema().
*/
function field_collection_schema() {
$schema['field_collection_item'] = array(
'description' => 'Stores information about field collection items.',
'fields' => array(
'item_id' => array(
'type' => 'serial',
'not null' => TRUE,
'description' => 'Primary Key: Unique field collection item ID.',
),
'revision_id' => array(
'type' => 'int',
'not null' => TRUE,
'description' => 'Default revision ID.',
),
'field_name' => array(
'description' => 'The name of the field on the host entity embedding this entity.',
'type' => 'varchar',
'length' => 32,
'not null' => TRUE,
),
'archived' => array(
'description' => 'Boolean indicating whether the field collection item is archived.',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
),
),
'primary key' => array(
'item_id',
),
);
$schema['field_collection_item_revision'] = array(
'description' => 'Stores revision information about field collection items.',
'fields' => array(
'revision_id' => array(
'type' => 'serial',
'not null' => TRUE,
'description' => 'Primary Key: Unique revision ID.',
),
'item_id' => array(
'type' => 'int',
'not null' => TRUE,
'description' => 'Field collection item ID.',
),
),
'primary key' => array(
'revision_id',
),
'indexes' => array(
'item_id' => array(
'item_id',
),
),
'foreign keys' => array(
'versioned_field_collection_item' => array(
'table' => 'field_collection_item',
'columns' => array(
'item_id' => 'item_id',
),
),
),
);
if (module_exists('entitycache')) {
$schema['cache_entity_field_collection_item'] = drupal_get_schema_unprocessed('system', 'cache');
$schema['cache_entity_field_collection_item']['description'] = 'Cache table used to store field_collection_item entity records.';
}
return $schema;
}
/**
* Implements hook_field_schema().
*/
function field_collection_field_schema($field) {
$columns = array(
'value' => array(
'type' => 'int',
'not null' => FALSE,
'description' => 'The field collection item id.',
),
'revision_id' => array(
'type' => 'int',
'not null' => FALSE,
'description' => 'The field collection item revision id.',
),
);
return array(
'columns' => $columns,
'indexes' => array(
'value' => array(
'value',
),
'revision_id' => array(
'revision_id',
),
),
);
}
/**
* Update the administer field collection permission machine name.
*/
function field_collection_update_7000() {
db_update('role_permission')
->fields(array(
'permission' => 'administer field collections',
))
->condition('permission', 'administer field-collections')
->execute();
}
/**
* Add revision support.
*/
function field_collection_update_7001() {
// Add revision_id column to field_collection_item table.
$revision_id_spec = array(
'type' => 'int',
'not null' => TRUE,
'description' => 'Default revision ID.',
// Set default to 0 temporarily.
'initial' => 0,
);
// Field may already exist due to bug in 7.x-1.0-beta5.
if (!db_field_exists('field_collection_item', 'revision_id')) {
db_add_field('field_collection_item', 'revision_id', $revision_id_spec);
}
// Initialize the revision_id to be the same as the item_id.
db_update('field_collection_item')
->expression('revision_id', 'item_id')
->execute();
// Add the archived column.
$archived_spec = array(
'description' => 'Boolean indicating whether the field collection item is archived.',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
);
// Field may already exist due to bug in 7.x-1.0-beta5.
if (!db_field_exists('field_collection_item', 'archived')) {
db_add_field('field_collection_item', 'archived', $archived_spec);
}
// Create the new table. It is important to explicitly define the schema here
// rather than use the hook_schema definition: http://drupal.org/node/150220.
$schema['field_collection_item_revision'] = array(
'description' => 'Stores revision information about field collection items.',
'fields' => array(
'revision_id' => array(
'type' => 'serial',
'not null' => TRUE,
'description' => 'Primary Key: Unique revision ID.',
),
'item_id' => array(
'type' => 'int',
'not null' => TRUE,
'description' => 'Field collection item ID.',
),
),
'primary key' => array(
'revision_id',
),
'indexes' => array(
'item_id' => array(
'item_id',
),
),
'foreign keys' => array(
'versioned_field_collection_item' => array(
'table' => 'field_collection_item',
'columns' => array(
'item_id' => 'item_id',
),
),
),
);
// Table may already exist due to bug in 7.x-1.0-beta5.
if (db_table_exists('field_collection_item_revision')) {
db_drop_table('field_collection_item_revision');
}
db_create_table('field_collection_item_revision', $schema['field_collection_item_revision']);
// Fill the new table with the correct data.
$items = db_select('field_collection_item', 'fci')
->fields('fci')
->execute();
foreach ($items as $item) {
// Update field_collection_item_revision table.
db_insert('field_collection_item_revision')
->fields(array(
'revision_id' => $item->item_id,
'item_id' => $item->item_id,
))
->execute();
}
// Update the field_collection_field_schema columns for all tables.
// Add a revision_id column.
$revision_id_spec['description'] = 'The field collection item revision id.';
// Because $value_column below can be null, so must $revision_id_column.
$revision_id_spec['not null'] = FALSE;
foreach (field_read_fields(array(
'type' => 'field_collection',
)) as $field_name => $field) {
$table_prefixes = array(
'field_data',
'field_revision',
);
foreach ($table_prefixes as $table_prefix) {
$table = sprintf('%s_%s', $table_prefix, $field_name);
$value_column = sprintf('%s_value', $field_name);
$revision_id_column = sprintf('%s_revision_id', $field_name);
// Field may already exist due to bug in 7.x-1.0-beta5.
if (!db_field_exists($table, $revision_id_column)) {
db_add_field($table, $revision_id_column, $revision_id_spec);
}
else {
db_change_field($table, $revision_id_column, $revision_id_column, $revision_id_spec);
}
// Initialize the revision_id to be the same as the item_id.
db_update($table)
->expression($revision_id_column, $value_column)
->execute();
}
}
// Need to get the system up-to-date so drupal_schema_fields_sql() will work.
$schema = drupal_get_schema('field_collection_item_revision', TRUE);
}
/**
* Remove orphaned field collection item entities.
*/
function field_collection_update_7002() {
// Loop over all fields and delete any orphaned field collection items.
foreach (field_read_fields(array(
'type' => 'field_collection',
)) as $field_name => $field) {
$select = db_select('field_collection_item', 'fci')
->fields('fci', array(
'item_id',
))
->condition('field_name', $field_name)
->condition('archived', 0);
$select
->leftJoin('field_data_' . $field_name, 'field', "field.{$field_name}_value = fci.item_id ");
$select
->isNull('field.entity_id');
$ids = $select
->execute()
->fetchCol();
entity_delete_multiple('field_collection_item', $ids);
drupal_set_message(t('Deleted @count orphaned field collection items.', array(
'@count' => count($ids),
)));
}
}
/**
* Update field_collection_field_schema columns for all tables.
*/
function field_collection_update_7003() {
// Revision_id column.
$revision_id_spec = array(
'type' => 'int',
'not null' => FALSE,
'description' => 'The field collection item revision id.',
'initial' => 0,
);
// Update the field_collection_field_schema columns for all tables,
// in case the buggy beta5 version of field_collection_update_7001()
// completed without complaint.
foreach (field_read_fields(array(
'type' => 'field_collection',
)) as $field_name => $field) {
$table_prefixes = array(
'field_data',
'field_revision',
);
foreach ($table_prefixes as $table_prefix) {
$table = sprintf('%s_%s', $table_prefix, $field_name);
$value_column = sprintf('%s_value', $field_name);
$revision_id_column = sprintf('%s_revision_id', $field_name);
db_change_field($table, $revision_id_column, $revision_id_column, $revision_id_spec);
}
}
// Need to get the system up-to-date so drupal_schema_fields_sql() will work.
$schema = drupal_get_schema('field_collection_item_revision', TRUE);
}
/**
* Add index on {$field_collection_field}_revision_id column for all tables.
*/
function field_collection_update_7004() {
// Update the field_collection_field_schema columns for all tables.
foreach (field_read_fields(array(
'type' => 'field_collection',
)) as $field_name => $field) {
$table_prefixes = array(
'field_data',
'field_revision',
);
foreach ($table_prefixes as $table_prefix) {
$table = sprintf('%s_%s', $table_prefix, $field_name);
$revision_id_column = sprintf('%s_revision_id', $field_name);
// Add index on revision_id column.
if (!db_index_exists($table, $revision_id_column)) {
db_add_index($table, $revision_id_column, array(
$revision_id_column,
));
}
}
}
}
/**
* Force the creation of the table cache_entity_field_collection_item.
*
* Update entity_update_7003() will attempt to install entitycache tables for
* existing modules, but it uses module_list() to get the list of available
* modules, which, when called from a database update, may not return
* field_collection since drupal is bootstrapped at a lower level.
*/
function field_collection_update_7005() {
if (module_exists('entitycache')) {
$entity_type = 'field_collection_item';
$table = 'cache_entity_' . $entity_type;
if (!db_table_exists($table)) {
$schema = drupal_get_schema_unprocessed('system', 'cache');
$schema['description'] = 'Cache table used to store' . $entity_type . ' entity records.';
db_create_table($table, $schema);
}
}
}
/**
* Ensures revision_id indexes are present at field_config table.
*/
function field_collection_update_7006() {
$result = db_query("SELECT id, field_name, data FROM {field_config} WHERE type = 'field_collection'");
foreach ($result as $field_config) {
$data = unserialize($field_config->data);
// Skip this record if the revision_id index is already present.
if (isset($data['indexes']['revision_id'])) {
continue;
}
// Otherwise, add the revision_id index and update the record.
$data['indexes']['revision_id'] = array(
'revision_id',
);
$data = serialize($data);
$num_updated = db_update('field_config')
->fields(array(
'data' => $data,
))
->condition('id', $field_config->id)
->execute();
// If for some reason the update failed, throw an exception.
if ($num_updated != 1) {
$t_args['@field'] = $field_config->field_name;
throw new DrupalUpdateException(t('An error was detected when attempting to update field configuration for field @field.', $t_args));
}
}
}
/**
* Add index on {$field_collection_field}_value column for all tables.
*/
function field_collection_update_7007() {
foreach (field_read_fields(array(
'type' => 'field_collection',
)) as $field_name => $field) {
if (!isset($field['indexes']['value'])) {
// Add index on the value column and update the field.
$field['indexes']['value'] = array(
'value',
);
field_update_field($field);
}
$table_prefixes = array(
'field_data',
'field_revision',
);
foreach ($table_prefixes as $table_prefix) {
$table = "{$table_prefix}_{$field_name}";
$value_column = "{$field_name}_value";
if (!db_index_exists($table, $value_column)) {
// Add index on the value column.
db_add_index($table, $value_column, array(
$value_column,
));
}
}
}
}
/**
* Update fields in field collections already set to use Entity Translation.
*/
function field_collection_update_7008() {
// Include FieldCollectionItemEntity class.
module_load_include('inc', 'field_collection', 'field_collection.entity');
$results = array();
foreach (field_info_fields() as $f_name => $field) {
if ($field['translatable'] == 1 && isset($field['bundles']['field_collection_item'])) {
$query = new EntityFieldQuery();
$query
->entityCondition('entity_type', 'field_collection_item')
->fieldLanguageCondition($f_name, LANGUAGE_NONE);
$query_result = $query
->execute();
if (isset($query_result['field_collection_item'])) {
$results += $query_result['field_collection_item'];
}
}
}
if (count($results)) {
$orphans = array();
$ids = array_keys($results);
$field_collection_items = entity_load('field_collection_item', $ids);
foreach ($field_collection_items as $item) {
/** @var FieldCollectionItemEntity $item */
if ($item
->hostEntity()) {
$item
->copyTranslations(LANGUAGE_NONE);
$item
->save(TRUE);
}
else {
$orphans[] = $item
->identifier();
}
}
if ($orphans) {
$count = count($orphans);
entity_delete_multiple('field_collection_item', $orphans);
drupal_set_message("Deleted {$count} orphaned field collection items.");
}
}
}
/**
* Update revisions created before revision support was implemented.
*/
function field_collection_update_7009(&$sandbox) {
$items_per_pass = 10;
$field_collection_fields = field_read_fields(array(
'type' => 'field_collection',
));
// If you don't have any field_collecton fields then skip this update.
if (empty($field_collection_fields)) {
return;
}
if (!isset($sandbox['current_field'])) {
$sandbox['field_collection_fields'] = array_keys($field_collection_fields);
$sandbox['current_field'] = 0;
$sandbox['current_field_collection_item'] = 0;
$sandbox['field_name'] = $sandbox['field_collection_fields'][$sandbox['current_field']];
$sandbox['inner_fields'] = field_read_instances(array(
'entity_type' => 'field_collection_item',
'bundle' => $sandbox['field_name'],
));
}
// Find field collection items with duplicate revision ids.
$query = db_select("field_revision_{$sandbox['field_name']}", 't')
->fields('t', array(
"{$sandbox['field_name']}_revision_id",
))
->range($sandbox['current_field_collection_item'], $items_per_pass)
->groupBy("t.{$sandbox['field_name']}_revision_id");
$query
->having("COUNT(t.{$sandbox['field_name']}_revision_id) >= 2");
$vids = $query
->execute()
->fetchCol();
// Each revision ID that occurs more than once.
foreach ($vids as $field_collection_duplicated_revision_id) {
// Find every instance of this revision ID.
$copies = db_select("field_revision_{$sandbox['field_name']}", 't')
->fields('t')
->condition("{$sandbox['field_name']}_revision_id", $field_collection_duplicated_revision_id)
->execute()
->fetchAllAssoc('revision_id');
$first_copy = reset($copies);
$field_collection_item_id = $first_copy->{"{$sandbox['field_name']}_value"};
// Find the currently used revision of this field collection item.
$field_collection_item_current_revision = db_select('field_collection_item', 'fci')
->fields('fci', array(
'revision_id',
))
->condition('item_id', $field_collection_item_id)
->execute()
->fetchField();
// Find new revisions of this field collection item that were made after
// revisions were enabled in update_7003.
$modern_revisions = db_select("field_revision_{$sandbox['field_name']}", 't')
->fields('t')
->condition("{$sandbox['field_name']}_revision_id", $field_collection_duplicated_revision_id, '<>')
->condition("{$sandbox['field_name']}_value", $field_collection_item_id)
->orderBy('revision_id')
->execute()
->fetchAllAssoc('revision_id');
// Intentionally skip the first instance as it doesn't need to be modified.
while (FALSE !== ($row_to_replace = next($copies))) {
$new_revision_id = _field_collection_update_7009_new_revision($field_collection_item_id, $row_to_replace, $sandbox['inner_fields'], $sandbox['field_name']);
// Create copies of inner fields with new revision number.
foreach ($sandbox['inner_fields'] as $field) {
// Get the data to copy.
$data_rows = db_select("field_revision_{$field['field_name']}", 't')
->fields('t')
->condition('entity_type', 'field_collection_item')
->condition('revision_id', $field_collection_duplicated_revision_id)
->execute();
// Add new copy of data with new revision id.
while ($each_row = $data_rows
->fetchAssoc()) {
$each_row['revision_id'] = $new_revision_id;
db_insert("field_revision_{$field['field_name']}")
->fields(array_keys($each_row), array_values($each_row))
->execute();
}
}
// Update the host's field data with new revision number.
db_update("field_revision_{$sandbox['field_name']}")
->fields(array(
"{$sandbox['field_name']}_revision_id" => $new_revision_id,
))
->condition('entity_type', $row_to_replace->entity_type)
->condition('revision_id', $row_to_replace->revision_id)
->condition('delta', $row_to_replace->delta)
->condition('language', $row_to_replace->language)
->execute();
if ($field_collection_item_current_revision == $field_collection_duplicated_revision_id) {
_field_collection_update_7009_update_data($new_revision_id, $field_collection_duplicated_revision_id);
// Update the current field collection item data in its host.
db_update("field_data_{$sandbox['field_name']}")
->fields(array(
'revision_id' => $new_revision_id,
))
->condition('revision_id', $field_collection_duplicated_revision_id)
->condition('entity_type', $row_to_replace->entity_type)
->execute();
}
}
foreach ($modern_revisions as $each_modern_revision) {
$new_revision_id = _field_collection_update_7009_new_revision($field_collection_item_id, $each_modern_revision, $sandbox['inner_fields'], $sandbox['field_name']);
// Update inner fields with new revision number.
foreach ($sandbox['inner_fields'] as $field) {
db_update("field_revision_{$field['field_name']}")
->fields(array(
'revision_id' => $new_revision_id,
))
->condition('revision_id', $each_modern_revision->{$sandbox['field_name'] . '_revision_id'})
->condition('entity_type', 'field_collection_item')
->execute();
}
// Update the host's field data with new revision number.
db_update("field_revision_{$sandbox['field_name']}")
->fields(array(
"{$sandbox['field_name']}_revision_id" => $new_revision_id,
))
->condition('entity_type', $each_modern_revision->entity_type)
->condition('revision_id', $each_modern_revision->revision_id)
->condition('delta', $each_modern_revision->delta)
->condition('language', $each_modern_revision->language)
->execute();
if ($field_collection_item_current_revision == $each_modern_revision->{"{$sandbox['field_name']}_revision_id"}) {
_field_collection_update_7009_update_data($new_revision_id, $field_collection_item_current_revision);
// Update the current field collection item data in its host.
db_update("field_data_{$sandbox['field_name']}")
->fields(array(
'revision_id' => $new_revision_id,
))
->condition('revision_id', $field_collection_item_current_revision)
->condition('entity_type', $each_modern_revision->entity_type)
->execute();
}
// Remove old copy of revision.
db_delete('field_collection_item_revision')
->condition('revision_id', $each_modern_revision->revision_id)
->execute();
}
$sandbox['current_field_collection_item']++;
}
$sandbox['#finished'] = 0;
if (count($vids) < $items_per_pass) {
$sandbox['current_field']++;
if ($sandbox['current_field'] == count($sandbox['field_collection_fields'])) {
$sandbox['#finished'] = 1;
return;
}
$sandbox['current_field_collection_item'] = 0;
$sandbox['field_name'] = $sandbox['field_collection_fields'][$sandbox['current_field']];
$sandbox['inner_fields'] = field_read_instances(array(
'entity_type' => 'field_collection_item',
'bundle' => $sandbox['field_name'],
));
}
}
/**
*
*/
function _field_collection_update_7009_new_revision($field_collection_item_id, $row_to_replace, $inner_fields, $field_name) {
// Add to field_collection_item_revision table.
$new_revision_id = db_insert('field_collection_item_revision')
->fields(array(
'item_id',
), array(
$field_collection_item_id,
))
->execute();
return $new_revision_id;
}
/**
*
*/
function _field_collection_update_7009_update_data($new_revision, $old_revision) {
// Update the current field collection item.
db_update('field_collection_item')
->fields(array(
'revision_id' => $new_revision,
))
->condition('revision_id', $old_revision)
->execute();
}
Functions
Name | Description |
---|---|
field_collection_field_schema | Implements hook_field_schema(). |
field_collection_schema | Implements hook_schema(). |
field_collection_update_7000 | Update the administer field collection permission machine name. |
field_collection_update_7001 | Add revision support. |
field_collection_update_7002 | Remove orphaned field collection item entities. |
field_collection_update_7003 | Update field_collection_field_schema columns for all tables. |
field_collection_update_7004 | Add index on {$field_collection_field}_revision_id column for all tables. |
field_collection_update_7005 | Force the creation of the table cache_entity_field_collection_item. |
field_collection_update_7006 | Ensures revision_id indexes are present at field_config table. |
field_collection_update_7007 | Add index on {$field_collection_field}_value column for all tables. |
field_collection_update_7008 | Update fields in field collections already set to use Entity Translation. |
field_collection_update_7009 | Update revisions created before revision support was implemented. |
_field_collection_update_7009_new_revision | |
_field_collection_update_7009_update_data |