diff --git a/serial.inc b/serial.inc index 28e12a3..6ba6cb0 100644 --- a/serial.inc +++ b/serial.inc @@ -41,14 +41,14 @@ function _serial_drop_table(array $field, array $instance) { } /** - * Renames serial table(s) when a content type us renamed. + * Renames serial table(s) when a entity bundle us renamed. * - * @param string $old_type - * An old node type machine name. - * @param string $new_type - * A new node type machine name. + * @param $bundle_old + * An old entity bundle machine name + * @param $bundle_new + * A new entity bundle machine name */ -function _serial_rename_tables($old_type, $new_type) { +function _serial_rename_tables($entity_type, $bundle_old, $bundle_new) { // Build the query to find all affected tables. $query = db_select('field_config', 'f') ->fields('f', array('field_name')); @@ -56,14 +56,17 @@ function _serial_rename_tables($old_type, $new_type) { $query->join( 'field_config_instance', 'i', - "f.field_name = i.field_name AND f.type = 'serial' AND i.bundle = '$new_type'" + "(f.field_name = i.field_name)" ); + $query->condition('f.type', 'serial'); + $query->condition('i.entity_type', $entity_type); + $query->condition('i.bundle', $bundle_new); // Rename each affected table. foreach ($query->addTag('node_access')->execute() as $record) { db_rename_table( - _serial_get_table_name($old_type, $record->field_name), - _serial_get_table_name($new_type, $record->field_name) + _serial_get_table_name($entity_type, $bundle_old, $record->field_name), + _serial_get_table_name($entity_type, $bundle_new, $record->field_name) ); } } @@ -80,22 +83,24 @@ function _serial_rename_tables($old_type, $new_type) { * The name of the assistant table of the specified field instance. */ function _serial_get_field_table_name(array $field, array $instance) { - return _serial_get_table_name($instance['bundle'], $field['field_name']); + return _serial_get_table_name($instance['entity_type'], $instance['bundle'], $field['field_name']); } /** * Gets the name of the assistant table for a specific field. * + * @param $entity_type + * Type of entity (e.g. node) * @param string $bundle - * The name of the entity type that contains the field. + * The name of the entity type that contains the field (e.g. content type) * @param string $field_name * The name of the field. * * @return string - * the name of the assistant table of the specified field. + * The name of the assistant table of the specified field. */ -function _serial_get_table_name($bundle, $field_name) { - return db_escape_table('serial_' . $bundle . '_' . $field_name); +function _serial_get_table_name($entity_type, $bundle, $field_name) { + return db_escape_table('serial_' . $entity_type . '_' . $bundle . '_' . $field_name); } /** @@ -128,8 +133,10 @@ function _serial_get_table_schema() { } /** - * Generates a unique serial value (unique per node type). + * Generates a unique serial value (unique per entity bundle). * + * @param $entity_type + * Type of entity (e.g. node) * @param string $bundle * Containing bundle (e.g. content type). * @param string $field_name @@ -140,9 +147,9 @@ function _serial_get_table_schema() { * @return int * the unique serial value number. */ -function _serial_generate_value($bundle, $field_name, $delete = TRUE) { +function _serial_generate_value($entity_type, $bundle, $field_name, $delete = TRUE) { // Get the name of the relevant table. - $table = _serial_get_table_name($bundle, $field_name); + $table = _serial_get_table_name($entity_type, $bundle, $field_name); // Insert a temporary record to get a new unique serial value. $uniqid = uniqid('', TRUE); @@ -165,49 +172,75 @@ function _serial_generate_value($bundle, $field_name, $delete = TRUE) { } /** - * Initializes the value of a new serial field in existing nodes. + * Initializes the value of a new serial field in existing entities. * * @todo Currently works only for nodes - should support comments and users. * + * @param $entity_type + * Type of entity (e.g. node) * @param string $bundle * Containing bundle (e.g. content type). * @param string $field_name * The field name. * * @return int - * Number of existing nodes that have been initialized. + * Number of existing entities that have been initialized. */ -function _serial_init_old_nodes($bundle, $field_name) { - $nodes = node_load_multiple(array(), array('type' => $bundle)); - - // Allocate a serial number for every old node. - foreach ($nodes as $node) { - $node->{$field_name} = array( - LANGUAGE_NONE => array( - array( - 'value' => _serial_generate_value($bundle, $field_name, FALSE), +function _serial_init_old_entities($entity_type, $bundle, $field_name) { + // Prepare meta data. + $entity_info = entity_get_info($entity_type); + $base_table = $entity_info['base table']; + $bundle_key = $entity_info['entity keys']['bundle']; + $id_key = $entity_info['entity keys']['id']; + + // @todo - What if $base_table or $id_key is empty? + + // Build the query. + $query = "SELECT $id_key FROM {$base_table} "; + if (!empty($bundle_key)) { + // Some entity types (e.g. user) do not have bundle. + $query .= "WHERE $bundle_key = :type "; + } + $query .= "ORDER BY $id_key"; + + // Execute the query. + // @todo - Which is better: EntityFieldQuery or db_query? + $results = db_query($query, array('type' => $bundle)); + + // Allocate a serial number for every old entity: + $count = 0; + foreach ($results as $result) { + $id = $result->{$id_key}; + if ($id > 0) { + // Check for valid id. Prevent anonymous user from being updated. + $entity = entity_load($entity_type, array($id)); + $entity->{$field_name} = array( + LANGUAGE_NONE => array( + array( + 'value' => _serial_generate_value($entity_type, $bundle, $field_name, FALSE), + ), ), - ), - ); - - node_save($node); + ); + entity_save($entity_type, $entity); + $count++; + } } - // Return the number of existing nodes that have been initialized. - return count($nodes); + // Return the number of existing entities that have been initialized. + return $count; } /** * Retrieves all the managed serial fields. * * @return array - * Pairs of node type name, field name. + * Result set containing entity type, entity bundle, field name. */ function _serial_get_all_fields() { $query = db_select('field_config', 'f'); $query->join('field_config_instance', 'i', 'i.field_name = f.field_name'); - return $query->fields('i', array('bundle', 'field_name')) + return $query->fields('i', array('entity_type', 'bundle', 'field_name')) ->condition('f.type', 'serial') ->condition('i.deleted', 0) ->execute() diff --git a/serial.install b/serial.install index e3abdcf..059ebce 100644 --- a/serial.install +++ b/serial.install @@ -37,7 +37,7 @@ function serial_schema() { $schema = array(); foreach (_serial_get_all_fields() as $field) { - $schema[_serial_get_table_name($field->bundle, $field->field_name)] = $table_schema; + $schema[_serial_get_table_name($field->entity_type, $field->bundle, $field->field_name)] = $table_schema; } // Return the schema of all the assistant tables (one per field instance). @@ -57,7 +57,7 @@ function serial_update_7130() { // Update the schema of old assistant tables. foreach (_serial_get_all_fields() as $field) { // Empty the table. - $table = _serial_get_table_name($field->bundle, $field->field_name); + $table = _serial_get_table_name($field->entity_type, $field->bundle, $field->field_name); db_delete($table)->execute(); // Drop nid field and key. @@ -69,3 +69,16 @@ function serial_update_7130() { db_add_unique_key($table, 'uniqid', array('uniqid')); } } + +/** + * Add 'node_' to all serial tables. + * + * Change from serial_{content type}_{field name} to serial_node_{content type}_{field name} + */ +function serial_update_7131() { + // All old serial tables are of 'node' entity type. + foreach (db_find_tables('serial_%') as $tablename) { + $tablename_add_node = preg_replace('/^serial_/', 'serial_node_', $tablename); + db_rename_table($tablename, $tablename_add_node); + } +} diff --git a/serial.module b/serial.module index 9567fab..2e766cd 100644 --- a/serial.module +++ b/serial.module @@ -33,10 +33,10 @@ function serial_field_create_instance($instance) { _serial_create_table($field, $instance); // Set serial values for old objects. - $old_count = _serial_init_old_nodes($instance['bundle'], $field['field_name']); + $old_count = _serial_init_old_entities($instance['entity_type'], $instance['bundle'], $field['field_name']); if ($old_count > 0) { - drupal_set_message(t('Serial values have been automatically set for %count existing nodes.', array( + drupal_set_message(t('Serial values have been automatically set for %count existing entities.', array( '%count' => $old_count, ))); } @@ -76,7 +76,7 @@ function serial_field_presave($entity_type, $entity, $field, $instance, $langcod if (empty($items)) { module_load_include('inc', 'serial'); - $items = array(array('value' => _serial_generate_value($instance['bundle'], $field['field_name']))); + $items = array(array('value' => _serial_generate_value($entity_type, $instance['bundle'], $field['field_name']))); } } @@ -100,13 +100,12 @@ function serial_node_presave($node) { } /** - * Implements hook_node_type_update(). + * Implements hook_field_attach_rename_bundle(). */ -function serial_node_type_update($info) { - // Handle content type rename: - if (isset($info->old_type) && ($info->old_type != $info->type)) { +function serial_field_attach_rename_bundle($entity_type, $bundle_old, $bundle_new) { + if ($bundle_old !== $bundle_new) { module_load_include('inc', 'serial'); - _serial_rename_tables($info->old_type, $info->type); + _serial_rename_tables($entity_type, $bundle_old, $bundle_new); } } @@ -184,3 +183,57 @@ function serial_field_widget(&$form, &$form_state, $field, $instance, $items, $d ), ); } + +/** + * Implements hook_tokens(). + * + * Replace token for generic entity type. + */ +function serial_tokens($type, $tokens, $data, $options) { + $replacements = array(); + $sanitize = !empty($options['sanitize']); + + $entity_info = entity_get_info($type); + // Make sure type is entity type. + if (empty($entity_info)) { + return $replacements; + } + + $entity_type = $type; + if (!empty($data[$entity_type])) { + // Generic entity. + $entity = $data[$entity_type]; + foreach ($tokens as $name => $original) { + // Convert token to field name. + $field_name = str_replace('-', '_', $name); + $field_info = field_info_field($field_name); + if ($field_info['type'] == 'serial') { + // Check if field is used in a pathauto pattern. If so, skip token replacement. + $pathauto_match = FALSE; + if (module_exists('pathauto')) { + $pattern = pathauto_pattern_load_by_entity($entity_type, $data[$entity_type]->type); + $path_items = explode('/', $pattern); + foreach ($path_items as $path_item) { + if (preg_match('/^\[(.*):field_(.*)\]$/', $path_item, $matches)) { + if ($field_name == 'field_' . $matches[2]) { + $pathauto_match = TRUE; + break; + } + } + } + } + if (!$pathauto_match) { + $items = field_get_items($entity_type, $entity, $field_name); + if (empty($items)) { + continue; + } + $item = reset($items); + $serial_value = $item['value']; + $replacements[$original] = $sanitize ? filter_xss($serial_value) : $serial_value; + } + } + } + } + + return $replacements; +}