cms_content_sync-3.0.x-dev/cms_content_sync.install

cms_content_sync.install
<?php

/**
 * @file
 * Install file for cms_content_sync.
 */

use Drupal\cms_content_sync\Controller\AuthenticationByUser;
use Drupal\cms_content_sync\Controller\ContentSyncSettings;
use Drupal\cms_content_sync\Entity\Flow;
use Drupal\cms_content_sync\Entity\Pool;
use Drupal\cms_content_sync\SyncCoreInterface\SyncCoreFactory;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Config\FileStorage;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Link;
use Drupal\Core\Site\Settings;
use Drupal\user\Entity\Role;
use Drupal\user\Entity\User;
use EdgeBox\SyncCore\Interfaces\IApplicationInterface;

/**
 * Common modules that need to execute before us:
 * - default : 0
 * - menu_link_content : 1
 * - content_translation : 10
 * - views : 10
 * - paragraphs : 11.
 */
define('CMS_CONTENT_SYNC_MODULE_WEIGHT', 50);

define('CMS_CONTENT_SYNC_USER_REQUIRED_PERMISSIONS', [
  'restful get cms_content_sync_sync_core_entity_item',
  'restful post cms_content_sync_sync_core_entity_item',
  'restful put cms_content_sync_sync_core_entity_item',
  'restful delete cms_content_sync_sync_core_entity_item',
  'restful get cms_content_sync_sync_core_entity_list',
  'restful get cms_content_sync_sync_core_site_status',
  'restful get cms_content_sync_sync_core_site_config',
]);

define('CMS_CONTENT_SYNC_REQUIRED_CONFIG', [
  'encrypt.profile.cms_content_sync',
  'key.key.cms_content_sync',
  'rest.resource.cms_content_sync_sync_core_entity_item',
  'rest.resource.cms_content_sync_sync_core_entity_list',
  'rest.resource.cms_content_sync_sync_core_site_config',
  'rest.resource.cms_content_sync_sync_core_site_status',
  'system.action.node_cms_content_sync_export_action',
  'user.role.cms_content_sync',
]);

/**
 * Update the weight of the Content Sync module. As Content Sync depends on
 * other modules being run before it, we need to make sure our hooks like
 * hook_form_alter are called after everyone else's.
 * Symptoms if not done include:
 * - Forms are partially still editable even if it should be forbidden, e.g. menu settings.
 */
function _cms_content_sync_set_module_weight() {
  module_set_weight('cms_content_sync', CMS_CONTENT_SYNC_MODULE_WEIGHT);
}

/**
 * Re-import the given config to reset it to defaults when they're changed in
 * the module.
 *
 * @param $configsNames
 * @param string $module
 */
function _cms_content_sync_update_config($configsNames) {
  $config_path = \Drupal::service('extension.list.module')->getPath('cms_content_sync') . '/config/install';
  $source = new FileStorage($config_path);
  $config_storage = Drupal::service('config.storage');

  foreach ($configsNames as $name) {
    $config_storage->write($name, $source->read($name));
  }
}

/**
 * Implements hook_install().
 *
 * - Creates the CMS Content Sync user and provides him with all required permissions.
 * - Sets module weight so we can hook in after all other content creation modules.
 * - Displays message to start setting up the site.
 */
function cms_content_sync_install() {
  $config_path = \Drupal::service('extension.list.module')->getPath('cms_content_sync') . '/config/install';
  $source = new FileStorage($config_path);
  $config_storage = Drupal::service('config.storage');

  $configsNames = [
    'key.key.cms_content_sync',
    'encrypt.profile.cms_content_sync',
  ];

  foreach ($configsNames as $name) {
    $config_storage->write($name, $source->read($name));
  }

  $username = 'CMS Content Sync';
  Drupal::moduleHandler()->alter('cms_content_sync_username', $username);
  $data = [
    'userName' => $username,
    'userPass' => \Drupal::service('password_generator')->generate(64),
  ];

  $user = User::create();
  $user->setUsername($data['userName']);
  $user->setPassword($data['userPass']);
  $user->enforceIsNew();
  $user->activate();
  $user->addRole('cms_content_sync');
  $user->save();

  // Store UID in key value table.
  Drupal::service('keyvalue.database')->get('cms_content_sync_user')->set('uid', intval($user->id()));

  $data = cms_content_sync_encrypt_values($data);
  $userData = Drupal::service('user.data');

  $userData->set('cms_content_sync', $user->id(), 'sync_data', $data);

  _cms_content_sync_set_module_weight();

  Drupal::messenger()->addStatus(
        new FormattableMarkup('Thanks for choosing Content Sync! Continue now with the site @registration.', [
          '@registration' => Link::createFromRoute('registration', 'cms_content_sync.site')->toString(),
        ])
    );
}

/**
 * Implements hook_uninstall().
 */
function cms_content_sync_uninstall() {
  // Delete all Flows.
  $flows = Flow::getAll(FALSE);
  foreach ($flows as $flow) {
    $flow->delete();
  }

  // Delete all Pools.
  $pools = Pool::getAll();
  foreach ($pools as $pool) {
    $pool->delete();
  }

  /**
   * @var \Drupal\Core\Config\CachedStorage $config_storage
   */
  $config_storage = Drupal::service('config.storage');

  // Drupal doesn't delete config automatically, so we need to ensure that
  // everything is deleted properly. Otherwise you may get a fatal error after
  // uninstalling the module about missing REST interfaces or you may not be
  // able to install the module again afterwards.
  $configsNames = [
    'key.key.cms_content_sync',
    'encrypt.profile.cms_content_sync',
    'rest.resource.cms_content_sync_entity_resource',
    'rest.resource.cms_content_sync_import_entity',
    'rest.resource.cms_content_sync_sync_core_entity_item',
    'rest.resource.cms_content_sync_sync_core_entity_list',
    'rest.resource.cms_content_sync_sync_core_site_status',
    'system.action.node_cms_content_sync_export_action',
    'user.role.cms_content_sync',
    'system.action.user_remove_role_action.cms_content_sync',
    'system.action.user_add_role_action.cms_content_sync',
  ];

  foreach ($configsNames as $name) {
    $config_storage->delete($name);
  }

  // Delete CMS Content Sync User.
  $user = User::load(_cms_content_sync_user_id());
  if (isset($user)) {
    $user->delete();
  }

  // Delete entry from key value table.
  Drupal::service('keyvalue.database')->get('cms_content_sync_user')->delete('uid');

  // Delete state data.
  $state = Drupal::state();
  $state->delete('cms_content_sync.base_url');
  $state->delete('cms_content_sync.site_id');
  $state->delete('cms_content_sync.site_uuid');
}

/**
 * Implements hook_requirements.
 *
 * @param $phase
 *
 * @return array
 */
function cms_content_sync_requirements($phase) {
  $requirements = [];
  if ('runtime' == $phase) {
    $config_service = \Drupal::service('config.factory');
    $missing_config = array_filter(CMS_CONTENT_SYNC_REQUIRED_CONFIG, function ($config) use ($config_service) {
      return !$config_service->get($config) || $config_service->get($config)->isNew();
    });
    if (count($missing_config)) {
      $requirements['cms_content_sync_configuration'] = [
        'title' => t('Content Sync: Configuration'),
        'value' => t('You are missing required configuration: @configuration.', [
          '@configuration' => '"' . join('", "', $missing_config) . '"',
        ]),
        'severity' => REQUIREMENT_ERROR,
      ];
    }

    // Show error when the Content Sync user doesn't have the Content Sync role.
    $users = Drupal::entityTypeManager()
      ->getStorage('user')
      ->loadByProperties([
        'name' => 'CMS Content Sync',
      ]);

    if (count($users)) {
      $user = reset($users);
      if (!$user->hasRole('cms_content_sync')) {
        $requirements['cms_content_sync_user_role_assigned'] = [
          'title' => t('Content Sync: User role assigned'),
          'value' => t('The service user "@username" is missing the role cms_content_sync.', [
            '@username' => $user->getAccountName(),
          ]),
          'severity' => REQUIREMENT_ERROR,
        ];
      }
      if (!$user->isActive()) {
        $requirements['cms_content_sync_user_active'] = [
          'title' => t('Content Sync: User active'),
          'value' => t('The service user "@username" is not active.', [
            '@username' => $user->getAccountName(),
          ]),
          'severity' => REQUIREMENT_ERROR,
        ];
      }
      $missing_permissions = array_filter(CMS_CONTENT_SYNC_USER_REQUIRED_PERMISSIONS, function ($permission) use ($user) {
        return !$user->hasPermission($permission);
      });
      if (count($missing_permissions)) {
        $requirements['cms_content_sync_user_permissions'] = [
          'title' => t('Content Sync: User permissions'),
          'value' => t('The service user "@username" is missing permissions @permissions.', [
            '@username' => $user->getAccountName(),
            '@permissions' => '"' . join('", "', $missing_permissions) . '"',
          ]),
          'severity' => REQUIREMENT_ERROR,
        ];
      }

      $auth = AuthenticationByUser::getInstance();
      $expected_password = $auth->getPassword();
      $hashed_password = $user->getPassword();

      $password_hasher = \Drupal::service('password');
      if (!$password_hasher->check($expected_password, $hashed_password)) {
        $requirements['cms_content_sync_user_password'] = [
          'title' => t('Content Sync: User password'),
          'value' => t('The service user "@username" password changed unexpectedly.', [
            '@username' => $user->getAccountName(),
          ]),
          'severity' => REQUIREMENT_ERROR,
        ];
      }
    }
    else {
      $requirements['cms_content_sync_user_available'] = [
        'title' => t('Content Sync: User available'),
        'value' => t('The service user "@username" is missing.', [
          '@username' => 'CMS Content Sync',
        ]),
        'severity' => REQUIREMENT_ERROR,
      ];
    }

    // Get Sync Core Version.
    try {
      $sync_core = SyncCoreFactory::getSyncCoreV2();
    }
    catch (\Exception $e) {
      $sync_core = NULL;
    }
    if ($sync_core) {
      $status = [];

      try {
        $status = $sync_core->getReportingService()->getStatus();
      }
      catch (Exception $e) {
        // Can't connect.
        $requirements['cms_content_sync_sync_core_status'] = [
          'title' => t('Content Sync: Sync Core'),
          'value' => t('Cannot connect to: @url', [
            '@url' => SyncCoreFactory::getSyncCoreV2Url(),
          ]),
          'severity' => REQUIREMENT_ERROR,
        ];
      }

      if ($status) {
        // Get module Version.
        $module_info = Drupal::service('extension.list.module')->getExtensionInfo('cms_content_sync');
        if (!empty($module_info['version'])) {
          $module_version = $module_info['version'];
          $module_version = preg_replace('@^\d\.x-(.*)$@', '$1', $module_version);
        }

        // Connected.
        if (!empty($module_version)) {
          $requirements['cms_content_sync_sync_core_status'] = [
            'title' => t('Content Sync: Sync Core'),
            'value' => t(
                      'Connected to v@sync_core_version: @url<br><br><em class="module-version">Content Sync Module Version: @module_version</em>',
                  [
                    '@url' => SyncCoreFactory::getSyncCoreV2Url(),
                    '@sync_core_version' => $status['version'],
                    '@module_version' => $module_version,
                  ]
            ),
            'severity' => REQUIREMENT_INFO,
          ];
        }
        // Connected but can't get module version.
        else {
          $requirements['cms_content_sync_sync_core_status'] = [
            'title' => t('Content Sync: Sync Core'),
            'value' => t(
                      'Connected to v@sync_core_version: @url<br><br><em class="no-module-version">The CMS Content Sync module version could not be determined. This ususally happens when the dev version of the module is being used, or Drupal\'s "Update manager" module is not enabled.</em>',
                  [
                    '@url' => SyncCoreFactory::getSyncCoreV2Url(),
                    '@sync_core_version' => $status['version'],
                  ]
            ),
            'severity' => REQUIREMENT_INFO,
          ];
        }
      }

      $all_flows = Flow::getAll();
      $outdated_flows = array_filter($all_flows, function (Flow $flow) {
        return $flow->getController()->needsEntityTypeUpdate();
      });
      if (count($outdated_flows)) {
        $names = [];
        foreach ($outdated_flows as $flow) {
          $names[] = $flow->label();
        }
        $names = join(", ", $names);
        $requirements['cms_content_sync_config_sync'] = [
          'title' => t('Content Sync: Config sync'),
          'value' => t(
            'Your configuration changed and must be exported to our service: <em class="outdated-flows">@flows</em>.',
            [
              '@flows' => $names,
            ]
          ),
          'severity' => REQUIREMENT_ERROR,
        ];
      }
    }
  }

  return $requirements;
}

/**
 * Implements hook_update_N().
 *
 * Increase the max length of the status entity source_url field to 1000 chars.
 */
function cms_content_sync_update_8035() {
  $entity_id = 'cms_content_sync_entity_status';
  $field_name = 'source_url';
  $new_length = 1000;
  // Update the schema.
  \Drupal::database()->schema()->changeField($entity_id, $field_name, $field_name, [
    'type' => 'varchar',
    'length' => $new_length,
  ]);
  // Get the field definitions.
  $field_definitions = \Drupal::service('entity_field.manager')->getBaseFieldDefinitions($entity_id);
  // Update the field definition.
  $source_url = $field_definitions[$field_name];
  $source_url->setSetting('max_length', $new_length);
  $source_url->setSetting('column_changes_handled', TRUE);
  // Update the entity definition.
  $definition_update_manager = \Drupal::entityDefinitionUpdateManager();
  $definition_update_manager->getEntityType($entity_id);
  $definition_update_manager->updateFieldStorageDefinition($source_url);

  return t("The $entity_id.$field_name field length has been increased from 255 to $new_length characters.");
}

/**
 * Implements hook_update_N().
 *
 * Ignore update hook.
 */
function cms_content_sync_update_8034() {
  return t("Done.");
}

/**
 * Implements hook_update_N();.
 *
 * Remove unused interfaces and permissions.
 */
function cms_content_sync_update_8033() {
  // Revoke unused permissions.
  _cms_content_sync_update_config([
    'user.role.cms_content_sync',
  ]);
  $role = Role::load('cms_content_sync');
  $role->revokePermission('restful get cms_content_sync_preview_resource');
  $role->revokePermission('restful get cms_content_sync_entity_resource');
  $role->revokePermission('post cms_content_sync_entity_resource');
  $role->revokePermission('patch cms_content_sync_entity_resource');
  $role->revokePermission('delete cms_content_sync_entity_resource');
  $role->save();

  // Delete unused config.
  Drupal::configFactory()->getEditable('rest.resource.cms_content_sync_entity_resource')->delete();
  Drupal::configFactory()->getEditable('rest.resource.cms_content_sync_import_entity')->delete();

  return 'Removed unused config and permissions.';
}

/**
 * Implements hook_update_N();.
 *
 * Register our new REST interface with the Sync Core for faster and more
 * user-friendly config exports.
 */
function cms_content_sync_update_8032() {
  // Update configs to make the new site status interface available.
  _cms_content_sync_update_config([
    'rest.resource.cms_content_sync_sync_core_site_config',
    'user.role.cms_content_sync',
  ]);

  // Add new rest interface permissions to the already existing content sync role.
  $role = Role::load('cms_content_sync');
  $role->grantPermission('restful get cms_content_sync_sync_core_site_config');
  $role->save();

  // Update the site details at the Sync Core so that the Sync Core knows we
  // now provide a site config interface.
  $pools = Pool::getAll();
  if (count($pools)) {
    reset($pools)->getClient()->updateSiteAtSyncCore();
  }

  return 'Added REST interface for retrieving the site config. Please export your Flow configs to the Sync Core!';
}

/**
 * Implements hook_update_N();.
 *
 * Make sure customers migrate their old Flows before upgrading to 3.x.
 */
function cms_content_sync_update_8031() {
  foreach (Flow::getAll(FALSE) as $flow) {
    if (Flow::VARIANT_SIMPLE !== $flow->variant) {
      throw new \Exception("Your Flow " . $flow->id . " is using an old Flow variant that is no longer supported. You need to update your Flows in 2.x before updating to 3.x.");
    }
  }

  return "All Flows are supported.";
}

/**
 * Implements hook_update_N();.
 *
 * Register the new REST interface for the site status.
 */
function cms_content_sync_update_8030() {
  // Update configs to makie the new site status interface available.
  _cms_content_sync_update_config([
    'rest.resource.cms_content_sync_sync_core_site_status',
    'user.role.cms_content_sync',
  ]);

  // Add new rest interface permissions to the already existing content sync role.
  $role = Role::load('cms_content_sync');
  $role->grantPermission('restful get cms_content_sync_sync_core_site_status');
  $role->save();

  // Update the site details at the Sync Core so that the Sync Core knows we
  // now provide a site status interface.
  $pools = Pool::getAll();
  if (count($pools)) {
    reset($pools)->getClient()->updateSiteAtSyncCore();
  }

  return 'Added REST interface for retrieving the site status. Please export your Flow configs to the Sync Core!';
}

/**
 * Implements hook_update_N();.
 *
 * Update the site details at the Sync Core to propagate new localization
 * query parameters at the REST interfaces; required for per-translation
 * requests to work.
 */
function cms_content_sync_update_8023() {
  $pools = Pool::getAll();
  if (count($pools)) {
    reset($pools)->getClient()->updateSiteAtSyncCore();
  }
}

/**
 * Implements hook_update_N();.
 *
 * Disable dynamic pool assignment by default for existing sites to avoid
 * content being deleted unintentionally.
 */
function cms_content_sync_update_8022() {
  ContentSyncSettings::getInstance()->disableDynamicPoolAssignment(TRUE);

  return 'Disabled dynamic pool assignment by default to avoid content being deleted unintentionally.';
}

/**
 * Implements hook_update_N();.
 *
 * Update Content Sync to v2.1.
 */
function cms_content_sync_update_8021() {
  /**
   * @var \Drupal\cms_content_sync\Entity\Flow[] $configurations
   */
  $configurations = \Drupal::entityTypeManager()
    ->getStorage('cms_content_sync_flow')
    ->loadMultiple();

  $config_factory = \Drupal::configFactory();

  $prop = "sync_entities";

  // Add the REST interface to access an individual entity.
  foreach ($configurations as $flow) {
    if ($flow->$prop) {
      // Add properties "variant", "type", "per_bundle_settings" and "simple_settings" to Flows.
      $config = $config_factory->getEditable('cms_content_sync.flow.' . $flow->id);

      // Set variant to the old default of per-bundle.
      $config->set('variant', Flow::VARIANT_PER_BUNDLE);
      $config->set('per_bundle_settings', []);

      // Migrate the old "sync_entities" property to the new "per_bundle_settings" property.
      foreach ($flow->$prop as $key => $settings) {
        $parts = explode('-', $key);
        if (count($parts) > 2) {
          [$type, $bundle, $property] = $parts;
          $config->set('per_bundle_settings' . '.' . $type . '.' . $bundle . '.properties.' . $property, $settings);
        }
        else {
          [$type, $bundle] = $parts;
          $config->set('per_bundle_settings' . '.' . $type . '.' . $bundle . '.settings', $settings);
        }
      }

      $flow->per_bundle_settings = $config->get('per_bundle_settings');
      // We can't use ->getController() yet because the variant wasn't set yet.
      // $controller = new FlowControllerPerBundle($flow);
      // $config->set('type', $controller->getType());
      throw new \Exception("This update is no longer available in 3.x or later.");

      // Delete deprecated property as it's no longer used.
      $config->set('sync_entities', NULL);

      // Save migrated Flow.
      $config->save(TRUE);
    }
  }

  // Add new rest interface permissions to the already existing content sync role.
  $role = Role::load('cms_content_sync');
  $role->grantPermission('restful get cms_content_sync_sync_core_entity_item');
  $role->grantPermission('restful post cms_content_sync_sync_core_entity_item');
  $role->grantPermission('restful put cms_content_sync_sync_core_entity_item');
  $role->grantPermission('restful delete cms_content_sync_sync_core_entity_item');
  $role->grantPermission('restful get cms_content_sync_sync_core_entity_list');
  $role->grantPermission('restful get cms_content_sync_sync_core_site_status');
  $role->save();

  return 'Added new properties to Flows and update the Content Sync role.';
}

/**
 * Implements hook_update_N();.
 *
 * Add the REST interface to access an individual entity.
 */
function cms_content_sync_update_8020() {
  _cms_content_sync_update_config([
    'rest.resource.cms_content_sync_sync_core_entity_item',
    'rest.resource.cms_content_sync_sync_core_entity_list',
    'user.role.cms_content_sync',
  ]);

  return 'Added REST interface for Sync Core v2.';
}

/**
 * Implements hook_update_N();.
 *
 * Move base_url to key_value store.
 */
function cms_content_sync_update_8013() {
  $base_url = \Drupal::config('cms_content_sync.settings')->get('cms_content_sync_base_url');
  \Drupal::state()->set('cms_content_sync.base_url', $base_url);
  \Drupal::configFactory()->getEditable('cms_content_sync.settings')->clear('cms_content_sync_base_url')->save();

  return 'Move base_url to key_value store.';
}

/**
 * Implements hook_update_N();.
 *
 * Move site id key_value store.
 */
function cms_content_sync_update_8012() {
  $site_id = \Drupal::config('cms_content_sync.settings')->get('cms_content_sync_site_id');
  \Drupal::state()->set('cms_content_sync.site_id', $site_id);
  \Drupal::configFactory()->getEditable('cms_content_sync.settings')->clear('cms_content_sync_site_id')->save();

  return 'Move site id to key_value store.';
}

/**
 * Unset parent_id handler for paragraphs as it's using a local ID and we re-set
 * it later anyway.
 */
function cms_content_sync_update_8011() {
  $prop = "sync_entities";

  foreach (Flow::getAll(FALSE) as $flow) {
    $changed = FALSE;
    foreach ($flow->$prop as $key => &$config) {
      if (2 !== substr_count($key, '-')) {
        continue;
      }

      [$entity_type, , $field_name] = explode('-', $key);

      if ('paragraph' === $entity_type && 'parent_id' === $field_name && isset($config['handler']) && 'ignore' !== $config['handler']) {
        $config['handler'] = 'ignore';
        $config['export'] = 'disabled';
        $config['import'] = 'disabled';
        $changed = TRUE;
      }
    }

    if ($changed) {
      $flow->save();
    }
  }

  return 'Removed parent_id property for paragraphs from all Flows. Please re-export your Flows.';
}

/**
 * Promote Site ID + Authentication type as a side-wide property rather than a setting per pool.
 */
function cms_content_sync_update_8010() {
  /**
   * Part 1: Authentication type. Saved as configuration so it can be deployed.
   */
  $authentication_type = NULL;
  $config_factory = Drupal::configFactory();

  // Deprecated, using as string to avoid error from deprecation.
  $prop = "authentication_type";

  // Check that all Site IDs are set to the same value in all pools.
  foreach (Pool::getAll() as $pool) {
    // In case someone runs this update late.
    if (!$pool->$prop) {
      continue;
    }

    if (!$authentication_type || IApplicationInterface::AUTHENTICATION_TYPE_BASIC_AUTH === $pool->$prop) {
      $authentication_type = $pool->$prop;
    }
  }

  if ($authentication_type) {
    $config_factory
      ->getEditable('cms_content_sync.settings')
      ->set('cms_content_sync_authentication_type', $authentication_type)
      ->save();
  }

  // Unset duplicate data now.
  foreach (Pool::getAll() as $pool) {
    $pool->$prop = NULL;
    $pool->save();
  }

  /**
   * Part 2: Site ID. Saved as State so it can't be deployed.
   */
  $site_id = NULL;
  $pool_site_id = NULL;
  $cms_content_sync_settings = Settings::get('cms_content_sync');

  $prop = "site_id";

  // Check that all Site IDs are set to the same value in all pools.
  foreach (Pool::getAll() as $pool) {
    // Check for overwritten pool site_id.
    if (isset($cms_content_sync_settings, $cms_content_sync_settings['pools'][$pool->id]['site_id'])) {
      $pool_site_id = $cms_content_sync_settings['pools'][$pool->id]['site_id'];
    }
    else {
      $pool_site_id = $pool->$prop;
    }

    // In case someone runs this update late.
    if (!$pool_site_id) {
      continue;
    }

    if ($site_id) {
      if ($site_id !== $pool_site_id) {
        throw new Exception('Site ID must be unique per site. Please update your pool configuration or settings.php configuration for the pool overrides to reflect that and try again.');
      }
    }
    else {
      $site_id = $pool_site_id;
    }
  }

  if ($site_id) {
    Drupal::state()->set('cms_content_sync.site_machine_name', $site_id);
  }

  // Verify everything's okay. Will also export the site's name for better usability.
  foreach (SyncCoreFactory::getAllSyncCores() as $core) {
    $core->registerSite();
  }

  // Unset duplicate data now.
  foreach (Pool::getAll() as $pool) {
    $pool->$prop = NULL;
    $pool->save();
  }

  return 'Changed site ID and authentication type to be set per site, not per pool.';
}

/**
 * Add index for status entities on entity_type and entity_uuid.
 */
function cms_content_sync_update_8009() {
  $spec = [
    'fields' => [
      'entity_type' => [
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
      ],
      'entity_uuid' => [
        'type' => 'varchar',
        'length' => 32,
        'not null' => TRUE,
      ],
    ],
  ];

  $fields = ['entity_type', 'entity_uuid'];
  $schema = Drupal::database()->schema();
  $schema->addIndex('cms_content_sync_entity_status', 'cms_content_sync__type_uuid', $fields, $spec);

  return 'Added index to entity status table to improve performance.';
}

/**
 * Merge error: Ignore update hook.
 *
 * @param mixed $sandbox
 */
function cms_content_sync_update_8008(&$sandbox) {
  return 'Done';
}

/**
 * Merge error; Ignore update hook.
 *
 * @param mixed $sandbox
 */
function cms_content_sync_update_8007(&$sandbox) {
  return 'Done';
}

/**
 * Rebuild menu cache to ensure route changes are taken into account.
 *
 * @param mixed $sandbox
 */
function cms_content_sync_update_8006(&$sandbox) {
  Drupal::service('cache_tags.invalidator')->invalidateTags(['config:system.menu.admin']);

  return 'Rebuild menu cache to ensure route changes are taken into account.';
}

/**
 * Update the module weight.
 *
 * @param mixed $sandbox
 */
function cms_content_sync_update_8005(&$sandbox) {
  _cms_content_sync_set_module_weight();

  return 'Updated module weight to execute hooks after most other modules.';
}

/**
 * Implements hook_update_N();.
 *
 * Update the REST interface for entities to allow Basic Auth.
 *
 * @param mixed $sandbox
 */
function cms_content_sync_update_8004(&$sandbox) {
  _cms_content_sync_update_config([
    'rest.resource.cms_content_sync_entity_resource',
  ]);

  return 'Added Basic Auth as allowed authentication method to entity resource.';
}

/**
 * Implements hook_update_N();.
 *
 * Delete unused rest interface configuration.
 *
 * @param mixed $sandbox
 */
function cms_content_sync_update_8003(&$sandbox) {
  Drupal::configFactory()->getEditable('rest.resource.cms_content_sync_preview_resource')->delete();
}

/**
 * Implements hook_update_N();.
 *
 * Add the new REST interface for manual import.
 *
 * @param mixed $sandbox
 */
function cms_content_sync_update_8002(&$sandbox) {
  _cms_content_sync_update_config([
    'rest.resource.cms_content_sync_import_entity',
  ]);

  return 'Installed manual entity import functionality.';
}

/**
 * Implements hook_update_N();.
 *
 * Update field type for cms_content_sync_entity_status entity. Fields: last_export, last_import.
 *
 * @param mixed $sandbox
 */
function cms_content_sync_update_8001(&$sandbox) {
  $entity_type_manager = Drupal::entityTypeManager();
  $bundle_of = 'cms_content_sync_entity_status';

  $storage = $entity_type_manager->getStorage($bundle_of);
  $bundle_definition = $entity_type_manager->getDefinition($bundle_of);
  $id_key = $bundle_definition->getKey('id');
  $table_name = $storage->getDataTable() ?: $storage->getBaseTable();
  $database = Drupal::database();
  $definition_manager = Drupal::entityDefinitionUpdateManager();

  // Store the existing values for last_export.
  $last_export_values = $database->select($table_name)
    ->fields($table_name, [$id_key, 'last_export'])
    ->execute()
    ->fetchAllKeyed();

  // Store the existing values for last_import.
  $last_import_values = $database->select($table_name)
    ->fields($table_name, [$id_key, 'last_import'])
    ->execute()
    ->fetchAllKeyed();

  // Clear out the values.
  $database->update($table_name)
    ->fields([
      'last_export' => NULL,
      'last_import' => NULL,
    ])
    ->execute();

  // Uninstall the old fields.
  $field_storage_definition_last_export = $definition_manager->getFieldStorageDefinition('last_export', $bundle_of);
  $definition_manager->uninstallFieldStorageDefinition($field_storage_definition_last_export);
  $field_storage_definition_last_import = $definition_manager->getFieldStorageDefinition('last_import', $bundle_of);
  $definition_manager->uninstallFieldStorageDefinition($field_storage_definition_last_import);

  // Prepare new fields.
  $new_last_export = BaseFieldDefinition::create('timestamp')
    ->setLabel(t('Last exported'))
    ->setDescription(t('The last time the entity got exported.'))
    ->setRequired(FALSE);

  $new_last_import = BaseFieldDefinition::create('timestamp')
    ->setLabel(t('Last import'))
    ->setDescription(t('The last time the entity got imported.'))
    ->setRequired(FALSE);

  // Create new fields.
  $definition_manager->installFieldStorageDefinition('last_export', $bundle_of, $bundle_of, $new_last_export);
  $definition_manager->installFieldStorageDefinition('last_import', $bundle_of, $bundle_of, $new_last_import);

  // Restore the values.
  foreach ($last_export_values as $id => $value) {
    $database->update($table_name)
      ->fields(['last_export' => $value])
      ->condition($id_key, $id)
      ->execute();
  }
  foreach ($last_import_values as $id => $value) {
    $database->update($table_name)
      ->fields(['last_import' => $value])
      ->condition($id_key, $id)
      ->execute();
  }
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc