diff --git a/core/includes/update.inc b/core/includes/update.inc index 2719634..8bcf18b 100644 --- a/core/includes/update.inc +++ b/core/includes/update.inc @@ -1480,6 +1480,33 @@ function update_config_manifest_add($config_prefix, array $ids) { } /** + * Removes configuration entities and the entry in the manifest file during + * updates. + * + * @param string $config_prefix + * The configuration entity prefix from the annotation. + * @param array $ids + * An array of configuration entities to add to the manifest. + */ +function update_config_remove_config($config_prefix, array $ids) { + $manifest = config('manifest.' . $config_prefix); + + // Add record to manifest for each config entity. Operate on the data array + // as a whole, because $manifest->get() would treat dots in ids as nesting. + $data = $manifest->get(); + foreach ($ids as $id) { + if (isset($data[$id])) { + config($config_prefix . $id)->delete(); + unset($data[$id]); + } + } + $manifest->setData($data); + + // Write manifest to disk. + $manifest->save(); +} + +/** * Updates 7.x variables to state records. * * Provides a generalized method to migrate variables from 7.x to 8.x's diff --git a/core/modules/field/field.install b/core/modules/field/field.install index dcf2b38..e9cb949 100644 --- a/core/modules/field/field.install +++ b/core/modules/field/field.install @@ -9,77 +9,46 @@ use Drupal\field\Plugin\Core\Entity\Field; /** - * Creates a field by writing directly to the database. + * Creates a field by writing directly to configuration. * * @ingroup update_api */ function _update_7000_field_create_field(&$field) { - // Merge in default values.` + $uuid = new Uuid(); + + // Merge in default values. $field += array( + 'id' => $field['field_name'], + 'uuid' => $uuid->generate(), 'entity_types' => array(), 'cardinality' => 1, 'translatable' => FALSE, 'locked' => FALSE, 'settings' => array(), 'indexes' => array(), - 'deleted' => FALSE, 'active' => TRUE, + 'status' => 1, + 'langcode' => 'und', ); - // Set storage. + // Set the storage. $field['storage'] = array( 'type' => 'field_sql_storage', - 'settings' => array(), 'module' => 'field_sql_storage', 'active' => TRUE, + 'settings' => array(), ); - // Fetch the field schema to initialize columns and indexes. The field module - // is not guaranteed to be loaded at this point. - module_load_install($field['module']); - $schema = (array) module_invoke($field['module'], 'field_schema', $field); - $schema += array('columns' => array(), 'indexes' => array()); - // 'columns' are hardcoded in the field type. - $field['columns'] = $schema['columns']; - // 'indexes' can be both hardcoded in the field type, and specified in the - // incoming $field definition. - $field['indexes'] += $schema['indexes']; - - // The serialized 'data' column contains everything from $field that does not - // have its own column and is not automatically populated when the field is - // read. - $data = $field; - unset($data['columns'], $data['field_name'], $data['type'], $data['active'], $data['module'], $data['storage_type'], $data['storage_active'], $data['storage_module'], $data['locked'], $data['cardinality'], $data['deleted']); - // Additionally, do not save the 'bundles' property populated by - // field_info_field(). - unset($data['bundles']); - - // Write the field to the database. - $record = array( - 'field_name' => $field['field_name'], - 'type' => $field['type'], - 'module' => $field['module'], - 'active' => (int) $field['active'], - 'storage_type' => $field['storage']['type'], - 'storage_module' => $field['storage']['module'], - 'storage_active' => (int) $field['storage']['active'], - 'locked' => (int) $field['locked'], - 'data' => serialize($data), - 'cardinality' => $field['cardinality'], - 'translatable' => (int) $field['translatable'], - 'deleted' => (int) $field['deleted'], - ); - // We don't use drupal_write_record() here because it depends on the schema. - $field_id = db_insert('field_config') - ->fields($record) - ->execute(); + // Save in config. + Drupal::config('field.field.' . $field['id']) + ->setData($field) + ->save(); + update_config_manifest_add('field.field', array($field['id'])); // Create storage for the field. This requires a field entity, but cannot use // the regular entity_create() function here. $field_entity = new Field($field); field_sql_storage_field_storage_create_field($field_entity); - - $field['id'] = $field_id; } /** @@ -102,18 +71,20 @@ function _update_7000_field_delete_field($field_name) { throw new Exception($t('This function can only be used to delete fields without data')); } // Delete all instances. - db_delete('field_config_instance') - ->condition('field_name', $field_name) - ->execute(); + $config_names = config_get_storage_names_with_prefix('field.instance'); + foreach ($config_names as $id) { + list($p1, $p2, $entity_type, $bundle, $field_name) = explode('.', $id); + if ($field_name == $field_name) { + update_config_remove_config('field.instance', $entity_type . '.' . $bundle . '.' . $field_name); + } + } // Nuke field data and revision tables. db_drop_table($table_name); db_drop_table('field_revision_' . $field_name); // Delete the field. - db_delete('field_config') - ->condition('field_name', $field_name) - ->execute(); + update_config_remove_config('field.field', $field_name); } /** @@ -125,11 +96,7 @@ function _update_7000_field_delete_field($field_name) { */ function _update_7000_field_delete_instance($field_name, $entity_type, $bundle) { // Delete field instance configuration data. - db_delete('field_config_instance') - ->condition('field_name', $field_name) - ->condition('entity_type', $entity_type) - ->condition('bundle', $bundle) - ->execute(); + update_config_remove_config('field.instance', $entity_type . '.' . $bundle . '.' . $field_name); // Nuke data. db_delete('field_data_' . $field_name) @@ -162,88 +129,85 @@ function _update_7000_field_delete_instance($field_name, $entity_type, $bundle) * @ingroup update_api */ function _update_7000_field_read_fields(array $conditions = array(), $key = 'id') { - $fields = array(); - $query = db_select('field_config', 'fc', array('fetch' => PDO::FETCH_ASSOC)) - ->fields('fc'); - foreach ($conditions as $column => $value) { - $query->condition($column, $value); + $matching_fields = array(); + + $config_names = config_get_storage_names_with_prefix('field.field'); + $deleted_fields = Drupal::state()->get('field.field.deleted') ?: array(); + // Ditch UUID keys, we will iterate through deleted fields using a numeric + // index. + $deleted_fields = array_values($deleted_fields); + + if (empty($config_names) && empty($deleted_fields)) { + return $matching_fields; } - foreach ($query->execute() as $record) { - $field = unserialize($record['data']); - $field['id'] = $record['id']; - $field['field_name'] = $record['field_name']; - $field['type'] = $record['type']; - $field['module'] = $record['module']; - $field['active'] = $record['active']; - $field['storage']['type'] = $record['storage_type']; - $field['storage']['module'] = $record['storage_module']; - $field['storage']['active'] = $record['storage_active']; - $field['locked'] = $record['locked']; - $field['cardinality'] = $record['cardinality']; - $field['translatable'] = $record['translatable']; - $field['deleted'] = $record['deleted']; - - $fields[$field[$key]] = $field; + + // Collect matching fields. + foreach ($config_names as $id) { + $field = config($id)->get(); + + if (!empty($conditions)) { + foreach ($conditions as $key => $value) { + if ($field[$key] != $value) { + continue 2; + } + } + } + + $matching_fields[$field[$key]] = $field; } - return $fields; + + return $matching_fields; } /** - * Writes a field instance directly to the database. + * Writes a field instance directly to configuration. * * @ingroup update_api */ function _update_7000_field_create_instance($field, &$instance) { + $uuid = new Uuid(); + // Merge in defaults. $instance += array( - 'field_id' => $field['id'], - 'field_name' => $field['field_name'], - 'deleted' => FALSE, 'description' => '', 'required' => FALSE, + 'id' => $instance['entity_type'] . '.' . $instance['bundle'] . '.' . $instance['field_name'], + 'uuid' => $uuid->generate(), + 'field_uuid' => $field['uuid'], + 'field_type' => $field['type'], + 'default_value' => array(), + 'default_value_function' => '', + 'settings' => array(), + 'widget' => array(), + 'status' => 1, + 'langcode' => 'und', ); - // The serialized 'data' column contains everything from $instance that does - // not have its own column and is not automatically populated when the - // instance is read. - $data = $instance; - unset($data['id'], $data['field_id'], $data['field_name'], $data['entity_type'], $data['bundle'], $data['deleted']); - - $record = array( - 'field_id' => $instance['field_id'], - 'field_name' => $instance['field_name'], - 'entity_type' => $instance['entity_type'], - 'bundle' => $instance['bundle'], - 'data' => serialize($data), - 'deleted' => (int) $instance['deleted'], - ); - $instance['id'] = db_insert('field_config_instance') - ->fields($record) - ->execute(); + // Save in config. + Drupal::config('field.instance.' . $instance['id']) + ->setData($instance) + ->save(); + update_config_manifest_add('field.instance', array($instance['id'])); } /** - * @addtogroup updates-7.x-to-8.x - * @{ - */ - -/** * Implements hook_update_dependencies(). */ function field_update_dependencies() { - // Convert Field API to ConfigEntities after: + // Convert Field API to ConfigEntities: $dependencies['field'][8003] = array( - // - Custom block bodies have been turned to fields. - 'block' => 8008, - // - User pictures have been turned to fields. - 'user' => 8011, - // - The {file_usage}.id column has moved to varchar. + // - After the {file_usage}.id column has moved to varchar. 'file' => 8001, ); return $dependencies; } /** + * @addtogroup updates-7.x-to-8.x + * @{ + */ + +/** * Empty update - moved into field_update_8003(). */ function field_update_8001() { diff --git a/core/modules/overlay/overlay.install b/core/modules/overlay/overlay.install index 588f871..29e6fa9 100644 --- a/core/modules/overlay/overlay.install +++ b/core/modules/overlay/overlay.install @@ -24,7 +24,7 @@ function overlay_enable() { function overlay_update_dependencies() { // Migrate users.data after User module prepared the tables. $dependencies['overlay'][8000] = array( - 'user' => 8011, + 'user' => 8016, ); return $dependencies; } diff --git a/core/modules/user/user.install b/core/modules/user/user.install index dca417c..9815191 100644 --- a/core/modules/user/user.install +++ b/core/modules/user/user.install @@ -373,6 +373,18 @@ function user_install_picture_field() { } /** + * Implements hook_update_dependencies(). + */ +function user_update_dependencies() { + // Convert user picture to field after the fields and instances + // are converted to ConfigEntities. + $dependencies['user'][8011] = array( + 'field' => 8003, + ); + return $dependencies; +} + +/** * @addtogroup updates-7.x-to-8.x * @{ */ @@ -707,10 +719,6 @@ function user_update_8011() { 'uri_scheme' => 'public', 'default_image' => FALSE, ), - 'storage' => array( - 'type' => 'field_sql_storage', - 'settings' => array(), - ), ); _update_7000_field_create_field($field); @@ -776,8 +784,11 @@ function user_update_8011() { 'image_link' => 'content', ), 'weight' => 0, - )) - ->save(); + )); + $display->set('content.member_for', array( + 'visible' => FALSE, + )); + $display->save(); update_config_manifest_add('entity.display', array($display->get('id'))); // Add file usage for the default field. @@ -787,20 +798,12 @@ function user_update_8011() { 'fid' => $default_image_fid, 'module' => 'image', 'type' => 'default_image', - 'id' => $field['id'], + 'id' => $field['uuid'], 'count' => 1, )) ->execute(); } - // Update the user bundle settings and hide the member_for extra field. - $settings = update_variable_get('field_bundle_settings_user__user'); - $settings['extra_fields']['display']['member_for']['compact'] = array( - 'weight' => 0, - 'visible' => FALSE, - ); - update_variable_set('field_bundle_settings_user__user', $settings); - // Delete old variables. update_variable_del('user_pictures'); update_variable_del('user_picture_path');