You are here

address.install in Address 8

Requirements and update functions for the address module.

File

address.install
View source
<?php

/**
 * @file
 * Requirements and update functions for the address module.
 */
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
use Drupal\Core\Entity\Sql\SqlContentEntityStorageException;
use Drupal\Core\Utility\UpdateException;
use Drupal\field\Entity\FieldConfig;

/**
 * Implements hook_requirements().
 */
function address_requirements($phase) {
  $requirements = [];
  if ($phase == 'install') {
    if (!class_exists('\\CommerceGuys\\Addressing\\AddressFormat\\AddressFormatRepository')) {
      $requirements['addressing_library'] = [
        'description' => t('Address requires the commerceguys/addressing library.'),
        'severity' => REQUIREMENT_ERROR,
      ];
    }
  }
  return $requirements;
}

/**
 * Remove the stored address formats, update field settings.
 */
function address_update_8100() {

  // Clear the caches to ensure the entity type is gone.
  \Drupal::entityTypeManager()
    ->clearCachedDefinitions();
  \Drupal::service('entity_type.repository')
    ->clearCachedDefinitions();

  // Remove the underlying config.
  $config_factory = \Drupal::configFactory();
  $names = $config_factory
    ->listAll('address.address_format.');
  foreach ($names as $name) {
    $config_factory
      ->getEditable($name)
      ->delete();
  }

  // Update the 'fields' setting of each address field.
  // Replace 'recipient' with the new name fields.
  $entity_field_manager = \Drupal::service('entity_field.manager');
  $entity_field_map = $entity_field_manager
    ->getFieldMapByFieldType('address');
  foreach ($entity_field_map as $entity_type_id => $fields) {
    foreach ($fields as $field_name => $field_info) {
      foreach ($field_info['bundles'] as $bundle) {
        $field = FieldConfig::loadByName($entity_type_id, $bundle, $field_name);
        if (!$field) {

          // This is a base field, nothing can be done.
          continue 2;
        }
        $used_fields = $field
          ->getSetting('fields');
        if (!empty($used_fields['recipient'])) {
          $used_fields['givenName'] = 'givenName';
          $used_fields['additionalName'] = 'additionalName';
          $used_fields['familyName'] = 'familyName';
        }
        else {

          // The recipient field wasn't enabled previously.
          $used_fields['givenName'] = '';
          $used_fields['additionalName'] = '';
          $used_fields['familyName'] = '';
        }
        unset($used_fields['recipient']);
        $field
          ->setSetting('fields', $used_fields);
        $field
          ->save();
      }
    }
  }
}

/**
 * Update subdivisions, split the recipient into given_name, family_name fields.
 */
function address_update_8101() {
  if (!class_exists('\\CommerceGuys\\Addressing\\UpdateHelper')) {
    throw new UpdateException('The commerceguys/addressing library must be updated before running this update.');
  }
  $processed_fields = [];
  $columns_to_add = [
    'given_name',
    'additional_name',
    'family_name',
  ];
  $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
  $address_definition = $field_type_manager
    ->getDefinition('address');

  /** @var \Drupal\address\Plugin\Field\FieldType\AddressItem $address_item_class */
  $address_item_class = $address_definition['class'];
  $schema = \Drupal::database()
    ->schema();
  $entity_type_manager = \Drupal::entityTypeManager();
  $entity_field_manager = \Drupal::service('entity_field.manager');
  $entity_field_map = $entity_field_manager
    ->getFieldMapByFieldType('address');

  // The key-value collection for tracking installed storage schema.
  $entity_storage_schema_sql = \Drupal::keyValue('entity.storage_schema.sql');
  $entity_definitions_installed = \Drupal::keyValue('entity.definitions.installed');
  foreach ($entity_field_map as $entity_type_id => $field_map) {
    $entity_storage = $entity_type_manager
      ->getStorage($entity_type_id);

    // Only SQL storage based entities are supported / throw known exception.
    if (!$entity_storage instanceof SqlContentEntityStorage) {
      continue;
    }
    $entity_type = $entity_type_manager
      ->getDefinition($entity_type_id);
    $field_storage_definitions = $entity_field_manager
      ->getFieldStorageDefinitions($entity_type_id);

    /** @var Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
    $table_mapping = $entity_storage
      ->getTableMapping($field_storage_definitions);

    // Only need field storage definitions of address fields.

    /** @var \Drupal\Core\Field\FieldStorageDefinitionInterface $field_storage_definition */
    foreach (array_intersect_key($field_storage_definitions, $field_map) as $field_storage_definition) {
      $field_name = $field_storage_definition
        ->getName();
      try {
        $table = $table_mapping
          ->getFieldTableName($field_name);
        $initial_from_field = $table_mapping
          ->getFieldColumnName($field_storage_definition, 'recipient');
      } catch (SqlContentEntityStorageException $e) {

        // Custom storage? Broken site? No matter what, if there is no table
        // or column, there's little we can do.
        continue;
      }

      // See if the field has a revision table.
      $revision_table = NULL;
      if ($entity_type
        ->isRevisionable() && $field_storage_definition
        ->isRevisionable()) {
        if ($table_mapping
          ->requiresDedicatedTableStorage($field_storage_definition)) {
          $revision_table = $table_mapping
            ->getDedicatedRevisionTableName($field_storage_definition);
        }
        elseif ($table_mapping
          ->allowsSharedTableStorage($field_storage_definition)) {
          $revision_table = $entity_type
            ->getRevisionDataTable() ?: $entity_type
            ->getRevisionTable();
        }
      }

      // Load the installed field schema so that it can be updated.
      $schema_key = "{$entity_type_id}.field_schema_data.{$field_name}";
      $field_schema_data = $entity_storage_schema_sql
        ->get($schema_key);
      $processed_fields[] = [
        $entity_type_id,
        $field_name,
      ];

      // Loop over each new column and add it as a schema column change.
      foreach ($columns_to_add as $column_id) {
        $column = $table_mapping
          ->getFieldColumnName($field_storage_definition, $column_id);

        // Add `initial_from_field` to the new spec, as this will copy over
        // the entire data.
        $field_schema = $address_item_class::schema($field_storage_definition);
        $spec = $field_schema['columns'][$column_id];

        // We will not seed data into `additional_name`.
        if ($column_id != 'additional_name') {
          $spec += [
            'initial_from_field' => $initial_from_field,
          ];
        }

        // Add the new column.
        $schema
          ->addField($table, $column, $spec);
        if ($revision_table) {
          $schema
            ->addField($revision_table, $column, $spec);
        }

        // Add the new column to the installed field schema.
        if ($field_schema_data) {
          $field_schema_data[$table]['fields'][$column] = $field_schema['columns'][$column_id];
          $field_schema_data[$table]['fields'][$column]['not null'] = FALSE;
          if ($revision_table) {
            $field_schema_data[$revision_table]['fields'][$column] = $field_schema['columns'][$column_id];
            $field_schema_data[$revision_table]['fields'][$column]['not null'] = FALSE;
          }
        }
      }

      // Save changes to the installed field schema.
      if ($field_schema_data) {
        $recipient_column = $table_mapping
          ->getFieldColumnName($field_storage_definition, 'recipient');
        unset($field_schema_data[$table]['fields'][$recipient_column]);
        if ($revision_table) {
          unset($field_schema_data[$revision_table]['fields'][$recipient_column]);
        }
        $entity_storage_schema_sql
          ->set($schema_key, $field_schema_data);
      }
      if ($table_mapping
        ->allowsSharedTableStorage($field_storage_definition)) {
        $key = "{$entity_type_id}.field_storage_definitions";
        if ($definitions = $entity_definitions_installed
          ->get($key)) {
          $definitions[$field_name] = $field_storage_definition;
          $entity_definitions_installed
            ->set($key, $definitions);
        }
      }

      // Once all columns added, and data copied. Delete the field.
      $schema
        ->dropField($table, $initial_from_field);
    }
  }

  // Used by address_post_update_convert_names_subdivisions.
  \Drupal::state()
    ->set('address_8101_processed', $processed_fields);
}

/**
 * Remove the stored zones.
 */
function address_update_8103() {

  // Clear the caches to ensure the entity type is gone.
  \Drupal::entityTypeManager()
    ->clearCachedDefinitions();
  \Drupal::service('entity_type.repository')
    ->clearCachedDefinitions();

  // Remove the underlying config.
  $config_factory = \Drupal::configFactory();
  $names = $config_factory
    ->listAll('address.zone.');
  foreach ($names as $name) {
    $config_factory
      ->getEditable($name)
      ->delete();
  }
}

/**
 * Transfers the default country code widget setting to the field config.
 */
function address_update_8104() {
  $entity_field_manager = \Drupal::service('entity_field.manager');
  $entity_field_map = $entity_field_manager
    ->getFieldMapByFieldType('address');
  foreach ($entity_field_map as $entity_type_id => $fields) {
    foreach ($fields as $field_name => $field_info) {
      foreach ($field_info['bundles'] as $bundle) {
        $field = FieldConfig::loadByName($entity_type_id, $bundle, $field_name);
        if (!$field) {

          // This is a base field, nothing can be done.
          continue 2;
        }
        $form_display = EntityFormDisplay::load("{$entity_type_id}.{$bundle}.default");
        $address_component = $form_display ? $form_display
          ->getComponent($field_name) : NULL;
        if (!$form_display || !$address_component) {

          // The bundle doesn't have a form display, or the field is hidden.
          continue;
        }
        if (empty($address_component['settings']['default_country'])) {

          // No default country has been specified.
          continue;
        }
        $default_country = $address_component['settings']['default_country'];
        if ($default_country == 'site_default') {
          $default_country = \Drupal::config('system.date')
            ->get('country.default');
        }

        // Remove the setting from the widget.
        $address_component['settings'] = [];
        $form_display
          ->setComponent($field_name, $address_component);
        $form_display
          ->save();

        // Set the default country on the field.
        if ($default_country) {
          $field
            ->setDefaultValue([
            [
              'country_code' => $default_country,
            ],
          ]);
          $field
            ->save();
        }
      }
    }
  }
}

Functions

Namesort descending Description
address_requirements Implements hook_requirements().
address_update_8100 Remove the stored address formats, update field settings.
address_update_8101 Update subdivisions, split the recipient into given_name, family_name fields.
address_update_8103 Remove the stored zones.
address_update_8104 Transfers the default country code widget setting to the field config.