diff --git a/serial.inc b/serial.inc index 28e12a3..e11cd7f 100644 --- a/serial.inc +++ b/serial.inc @@ -41,29 +41,31 @@ function _serial_drop_table(array $field, array $instance) { } /** - * Renames serial table(s) when a content type us renamed. - * - * @param string $old_type - * An old node type machine name. - * @param string $new_type - * A new node type machine name. + * Renames serial table(s) when a entity bundle us renamed. + * + * @param string $entity_type + * Type of entity. + * @param string $bundle_old + * An old entity bundle machine name. + * @param string $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')); - $query->join( - 'field_config_instance', - 'i', - "f.field_name = i.field_name AND f.type = 'serial' AND i.bundle = '$new_type'" - ); + $query->join('field_config_instance', 'i', '(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 +82,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 string $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}"); } /** @@ -109,16 +113,17 @@ function _serial_get_table_schema() { 'fields' => array( 'sid' => array( 'type' => 'serial', - 'unsigned' => TRUE, 'not null' => TRUE, + 'unsigned' => TRUE, 'description' => 'The atomic serial field.', ), 'uniqid' => array( - 'description' => 'Unique temporary allocation Id.', 'type' => 'varchar', 'length' => 23, + 'default' => '', 'not null' => TRUE, - 'default' => ''), + 'description' => 'Unique temporary allocation Id.', + ), ), 'primary key' => array('sid'), 'unique keys' => array( @@ -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 string $entity_type + * Type of entity (e.g. node) * @param string $bundle * Containing bundle (e.g. content type). * @param string $field_name @@ -140,10 +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); $sid = db_insert($table) @@ -165,49 +171,65 @@ function _serial_generate_value($bundle, $field_name, $delete = TRUE) { } /** - * Initializes the value of a new serial field in existing nodes. - * - * @todo Currently works only for nodes - should support comments and users. + * Initializes the value of a new serial field in existing entities. * + * @param string $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) { + $query = new EntityFieldQuery(); + $query->entityCondition('entity_type', $entity_type) + ->fieldCondition($field_name); + + // The "comment" entity type does not support bundle conditions. + // @see https://api.drupal.org/api/drupal/includes!entity.inc/function/EntityFieldQuery%3A%3AentityCondition/7 + if ('comment' !== $entity_type) { + $query->entityCondition('bundle', $bundle); + } + + $results = $query->execute(); + + if (!empty($results[$entity_type])) { + foreach ($results[$entity_type] as $entity) { + list($id, , $bundle) = entity_extract_ids($entity_type, $entity); + + $entity = entity_load_unchanged($entity_type, $id); + $entity->{$field_name} = array( + LANGUAGE_NONE => array( + array( + 'value' => _serial_generate_value($entity_type, $bundle, $field_name, FALSE), + ), ), - ), - ); + ); - node_save($node); + field_attach_insert($entity_type, $entity); + } + + return count($results[$entity_type]); } - // Return the number of existing nodes that have been initialized. - return count($nodes); + return 0; } /** * Retrieves all the managed serial fields. * - * @return array - * Pairs of node type name, field name. + * @return string[] + * 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.info b/serial.info index 27df301..d25f723 100644 --- a/serial.info +++ b/serial.info @@ -2,6 +2,5 @@ name = Serial description = Defines atomic auto increment (serial) field type. package = Fields core = 7.x -dependencies[] = field -files[] = serial.module +dependencies[] = field diff --git a/serial.install b/serial.install index e3abdcf..7bb9231 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,17 @@ function serial_update_7130() { db_add_unique_key($table, 'uniqid', array('uniqid')); } } + +/** + * Add 'node_' to all existing serial tables. + * + * Change name: + * 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 $table) { + db_rename_table($table, preg_replace('/^serial_/', 'serial_node_', $table)); + } +} diff --git a/serial.module b/serial.module index 9567fab..079018b 100644 --- a/serial.module +++ b/serial.module @@ -24,7 +24,7 @@ function serial_field_info() { /** * Implements hook_field_create_instance(). */ -function serial_field_create_instance($instance) { +function serial_field_create_instance(array $instance) { $field = field_read_field($instance['field_name']); if ('serial' == $field['type']) { @@ -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, ))); } @@ -46,7 +46,7 @@ function serial_field_create_instance($instance) { /** * Implements hook_field_delete_instance(). */ -function serial_field_delete_instance($instance) { +function serial_field_delete_instance(array $instance) { $field = field_read_field($instance['field_name']); if ('serial' == $field['type']) { @@ -59,7 +59,7 @@ function serial_field_delete_instance($instance) { /** * Implements hook_form_alter(). */ -function serial_form_alter(&$form, $form_state, $form_id) { +function serial_form_alter(array &$form, array &$form_state, $form_id) { if ('field_ui_field_settings_form' == $form_id && 'serial' == $form['field']['type']['#value']) { drupal_set_message(t('Serial field %field has been created.', array( '%field' => $form['field']['field_name']['#value'], @@ -72,11 +72,15 @@ function serial_form_alter(&$form, $form_state, $form_id) { /** * Implements hook_field_presave(). */ -function serial_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) { +function serial_field_presave($entity_type, $entity, array $field, array $instance, $langcode, array &$items) { 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 +104,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); } } @@ -125,7 +128,7 @@ function serial_field_formatter_info() { /** * Implements hook_field_formatter_view(). */ -function serial_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) { +function serial_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, array $items, $display) { $element = array(); // Define the field contents for the single default formatter. @@ -157,7 +160,7 @@ function serial_theme() { /** * Theme function for the default formatter. */ -function theme_serial_formatter_default($variables) { +function theme_serial_formatter_default(array $variables) { return $variables['serial_id']; } @@ -176,7 +179,7 @@ function serial_field_widget_info() { /** * Implements hook_field_widget(). */ -function serial_field_widget(&$form, &$form_state, $field, $instance, $items, $delta = 0) { +function serial_field_widget(array &$form, array &$form_state, array $field, array $instance, array $items, $delta = 0) { return array( 'value' => array( '#type' => 'hidden', @@ -184,3 +187,45 @@ function serial_field_widget(&$form, &$form_state, $field, $instance, $items, $d ), ); } + +/** + * Implements hook_tokens(). + * + * Replace token for generic entity type. + */ +function serial_tokens($type, array $tokens, array $data = array(), array $options = array()) { + $entity_info = entity_get_info($type); + $replacements = array(); + + if (empty($entity_info) || empty($data[$type])) { + return $replacements; + } + + list(, , $bundle) = entity_extract_ids($type, $data[$type]); + $pathauto = module_exists('pathauto'); + + foreach ($tokens as $name => $original) { + // Convert token to field name. + $field_name = str_replace('-', '_', $name); + $field_info = field_info_field($field_name); + + if ('serial' === $field_info['type']) { + continue; + } + + if ($pathauto && strpos(pathauto_pattern_load_by_entity($type, $bundle), "$type:$field_name") !== FALSE) { + continue; + } + + /* @var array $items */ + $items = field_get_items($type, $data[$type], $field_name); + + if (empty($items)) { + continue; + } + + $replacements[$original] = $items[0]['value']; + } + + return $replacements; +}