SU-SWS/stanford_profile

View on GitHub
stanford_profile.install

Summary

Maintainability
Test Coverage
<?php

/**
 * @file
 * stanford_profile.install
 */

use Drupal\Core\Menu\MenuTreeParameters;
use Drupal\node\NodeInterface;
use Drupal\field\Entity\FieldConfig;

/**
 * Save the system pages from the original config values into state.
 */
function stanford_profile_update_8002() {
  $state = \Drupal::state();
  $state->set('stanford_profile.403_page', '/node/3');
  $state->set('stanford_profile.404_page', '/node/2');
  $state->set('stanford_profile.front_page', '/node/1');
}

/**
 * Create the new layout paragraph type.
 */
function stanford_profile_update_9000(&$sandbox) {
  \Drupal::service('module_installer')->install([
    'layout_paragraphs',
    'stanford_layout_paragraphs',
  ]);
  $plugins = [
    'layout_paragraphs' => [
      'enabled' => TRUE,
      'available_layouts' => [
        'layout_paragraphs_1_column' => '1 Column',
        'layout_paragraphs_2_column' => '2 Column',
        'layout_paragraphs_3_column' => '3 Column',
      ],
    ],
  ];

  /** @var \Drupal\paragraphs\ParagraphsTypeInterface $paragraph_type */
  $paragraph_type = \Drupal::entityTypeManager()
    ->getStorage('paragraphs_type')
    ->create([
      'uuid' => 'c935e784-07eb-4fbf-afab-f687901abe5a',
      'id' => 'stanford_layout',
      'label' => 'Layout',
    ]);
  $paragraph_type->set('behavior_plugins', $plugins);
  $paragraph_type->save();
}

/**
 * Install Claro theme and uninstall Seven.
 */
function stanford_profile_update_9001() {
  /** @var \Drupal\Core\Extension\ThemeInstallerInterface $theme_installer */
  $theme_installer = \Drupal::service('theme_installer');
  $theme_installer->install(['claro', 'stanford_profile_admin']);
  \Drupal::configFactory()
    ->getEditable('system.theme')
    ->set('admin', 'stanford_profile_admin')
    ->save();
  try {
    $theme_installer->uninstall(['seven']);
  }
  catch (\Exception $e) {
    // Theme was already uninstalled.
  }
}

/**
 * Correct path aliases that somehow are incorrectly formatted.
 */
function stanford_profile_update_9004() {
  $database = \Drupal::database();
  $query = $database->select('path_alias', 'p')
    ->fields('p');
  $conditions = $query->orConditionGroup()
    ->condition('alias', '%http:/%', 'LIKE')
    ->condition('alias', '%https:/%', 'LIKE');
  $query->condition($conditions);
  $results = $query->execute();

  while ($row = $results->fetchAssoc()) {
    $new_alias = trim(preg_replace('/:\/([a-z0-9])/', '://$1', $row['alias']), '/');
    if (!str_starts_with($new_alias, 'http')) {
      throw new \Exception('Unknown path alias pattern to correct');
    }
    $new_alias = parse_url($new_alias);

    if (empty($new_alias['path'])) {
      throw new \Exception('Unknown path alias pattern to correct');
    }
    $new_alias = $new_alias['path'];

    $database->update('path_alias')
      ->fields(['alias' => $new_alias])
      ->condition('id', $row['id'])
      ->execute();
    $database->update('path_alias_revision')
      ->fields(['alias' => $new_alias])
      ->condition('id', $row['id'])
      ->execute();
  }
}

/**
 * Migrate Basic Page react paragraphs to layout paragraphs.
 */
function stanford_profile_update_9005(&$sandbox) {
  $node_storage = \Drupal::entityTypeManager()
    ->getStorage('node');
  if (!isset($sandbox['count'])) {
    $nids = $node_storage->getQuery()
      ->accessCheck(FALSE)
      ->condition('type', 'stanford_page')
      ->sort('created')
      ->execute();
    $sandbox['nids'] = $nids;
    $sandbox['count'] = count($sandbox['nids']);
  }
  drupal_static_reset();
  $row_storage = \Drupal::entityTypeManager()->getStorage('paragraph_row');
  $paragraph_storage = \Drupal::entityTypeManager()->getStorage('paragraph');
  $node_ids = array_splice($sandbox['nids'], 0, 25);

  /** @var \Drupal\node\NodeInterface[] $nodes */
  $nodes = $node_storage->loadMultiple($node_ids);
  $delete_entities = [];
  foreach ($nodes as $node) {
    $changed_time = $node->getChangedTime();
    $new_components = [];
    /** @var \Drupal\Core\Field\EntityReferenceFieldItemListInterface $row */
    foreach ($node->get('su_page_components') as $row) {
      $row_entity = $row_storage->loadRevision($row->get('target_revision_id')
        ->getString());

      $delete_entities[] = $row_entity;
      $number_of_items = min($row_entity->get('su_page_components')
        ->count(), 3);
      $layout_id = "layout_paragraphs_{$number_of_items}_column";

      $new_row_entity = $paragraph_storage->create(['type' => 'stanford_layout']);
      $new_row_entity->setBehaviorSettings('layout_paragraphs', [
        'layout' => $layout_id,
        'config' => ['label' => ''],
        'parent_uuid' => NULL,
        'region' => NULL,
      ]);
      $new_row_entity->setParentEntity($node, 'su_page_components');
      $new_row_entity->save();

      $new_components[] = [
        'target_id' => $new_row_entity->id(),
        'entity' => $new_row_entity,
      ];

      /** @var \Drupal\Core\Field\EntityReferenceFieldItemListInterface $row_item */
      foreach ($row_entity->get('su_page_components') as $delta => $row_item) {
        /** @var \Drupal\paragraphs\ParagraphInterface $paragraph */
        $paragraph = $paragraph_storage->loadRevision($row_item->get('target_revision_id')
          ->getString());
        $behaviors = $paragraph->getAllBehaviorSettings();
        unset($behaviors['react']);
        $behaviors['layout_paragraphs'] = [
          'parent_uuid' => $new_row_entity->uuid(),
          'region' => _stanford_profile_update_9005_get_item_region($delta, $layout_id),
        ];
        $new_paragraph = $paragraph->createDuplicate();
        $new_paragraph->enforceIsNew();
        $new_paragraph->setParentEntity($node, 'su_page_components');
        $new_paragraph->setAllBehaviorSettings($behaviors);
        $new_paragraph->save();

        $new_components[] = [
          'target_id' => $new_paragraph->id(),
          'entity' => $new_paragraph,
        ];
        $delete_entities[] = $paragraph;
      }
    }
    $node->set('su_page_components', $new_components)->save();
    _stanford_profile_reset_node_changed_time($node, $changed_time);
  }
  foreach ($delete_entities as $entity) {
    $entity->delete();
  }
  $sandbox['#finished'] = empty($sandbox['nids']) ? 1 : ($sandbox['count'] - count($sandbox['nids'])) / $sandbox['count'];
}

/**
 * Migrate Publications react paragraphs to layout paragraphs.
 */
function stanford_profile_update_9006(&$sandbox) {
  $node_storage = \Drupal::entityTypeManager()
    ->getStorage('node');
  if (!isset($sandbox['count'])) {
    $nids = $node_storage->getQuery()
      ->accessCheck(FALSE)
      ->condition('type', 'stanford_publication')
      ->execute();
    $sandbox['nids'] = $nids;
    $sandbox['count'] = count($sandbox['nids']);
  }

  $row_storage = \Drupal::entityTypeManager()->getStorage('paragraph_row');
  $paragraph_storage = \Drupal::entityTypeManager()->getStorage('paragraph');
  $node_ids = array_splice($sandbox['nids'], 0, 25);

  /** @var \Drupal\node\NodeInterface[] $nodes */
  $nodes = $node_storage->loadMultiple($node_ids);
  $delete_entities = [];
  foreach ($nodes as $node) {
    $changed_time = $node->getChangedTime();
    $new_components = [];
    /** @var \Drupal\Core\Field\EntityReferenceFieldItemListInterface $row */
    foreach ($node->get('su_publication_components') as $row) {
      $row_entity = $row_storage->load($row->get('target_id')->getString());
      $delete_entities[] = $row_entity;
      $number_of_items = $row_entity->get('su_pubs_components')->count();
      $layout_id = "layout_paragraphs_{$number_of_items}_column";

      $new_row_entity = $paragraph_storage->create(['type' => 'stanford_layout']);
      $new_row_entity->setBehaviorSettings('layout_paragraphs', [
        'layout' => $layout_id,
        'config' => ['label' => ''],
        'parent_uuid' => NULL,
        'region' => NULL,
      ]);
      $new_row_entity->setParentEntity($node, 'su_publication_components');
      $new_row_entity->save();

      $new_components[] = [
        'target_id' => $new_row_entity->id(),
        'target_revision_id' => $new_row_entity->getRevisionId(),
      ];

      /** @var \Drupal\Core\Field\EntityReferenceFieldItemListInterface $row_item */
      foreach ($row_entity->get('su_pubs_components') as $delta => $row_item) {
        /** @var \Drupal\paragraphs\ParagraphInterface $paragraph */
        $paragraph = $paragraph_storage->load($row_item->get('target_id')
          ->getString());
        $behaviors = $paragraph->getAllBehaviorSettings();
        unset($behaviors['react']);
        $behaviors['layout_paragraphs'] = [
          'parent_uuid' => $new_row_entity->uuid(),
          'region' => _stanford_profile_update_9005_get_item_region($delta, $layout_id),
        ];
        $new_paragraph = $paragraph->createDuplicate();
        $new_paragraph->enforceIsNew();
        $new_paragraph->setParentEntity($node, 'su_publication_components');
        $new_paragraph->setAllBehaviorSettings($behaviors);
        $new_paragraph->save();

        $new_components[] = [
          'target_id' => $new_paragraph->id(),
          'target_revision_id' => $new_paragraph->getRevisionId(),
        ];
        $delete_entities[] = $paragraph;
      }
    }

    $node->set('su_publication_components', $new_components)->save();
    _stanford_profile_reset_node_changed_time($node, $changed_time);
  }
  foreach ($delete_entities as $entity) {
    $entity->delete();
  }
  $sandbox['#finished'] = empty($sandbox['nids']) ? 1 : ($sandbox['count'] - count($sandbox['nids'])) / $sandbox['count'];
}

/**
 * Get the items new region in the layout paragraphs layout.
 *
 * @param int $delta
 *   Position of the item in the row.
 * @param string $layout_id
 *   Parent layout id.
 *
 * @return string
 *   New region.
 */
function _stanford_profile_update_9005_get_item_region(int $delta, string $layout_id): string {
  switch ($layout_id) {
    case 'layout_paragraphs_2_column':
      return $delta ? 'right' : 'left';

    case 'layout_paragraphs_3_column':
      $delta_regions = ['left', 'main', 'right', 'right', 'right'];
      return $delta_regions[$delta];
  }
  return 'main';
}

/**
 * Update pages with custom layout builder settings.
 */
function stanford_profile_update_9007(&$sandbox) {
  $node_storage = \Drupal::entityTypeManager()
    ->getStorage('node');
  if (!isset($sandbox['count'])) {
    $nids = $node_storage->getQuery()
      ->accessCheck(FALSE)
      ->condition('layout_builder__layout', NULL, 'IS NOT NULL')
      ->execute();
    $sandbox['nids'] = $nids;
    $sandbox['count'] = count($sandbox['nids']);
  }

  $node_ids = array_splice($sandbox['nids'], 0, 25);
  /** @var \Drupal\node\NodeInterface[] $nodes */
  $nodes = $node_storage->loadMultiple($node_ids);

  $database = \Drupal::database();
  $convert_fields = [
    'field_block:node:stanford_event:su_event_components',
    'field_block:node:stanford_event_series:su_event_series_components',
    'field_block:node:stanford_news:su_news_components',
    'field_block:node:stanford_page:su_page_components',
    'field_block:node:stanford_person:su_person_components',
    'field_block:node:stanford_person:su_person_components',
    'field_block:node:stanford_publication:su_publication_components',
  ];
  foreach ($nodes as $node) {
    $changed_time = $node->getChangedTime();
    $save_node = FALSE;
    /** @var \Drupal\layout_builder\Field\LayoutSectionItemList $layout */
    $layout = $node->get('layout_builder__layout');
    foreach ($layout->getSections() as $section) {
      foreach ($section->getComponents() as $component) {
        $config = $component->get('configuration');
        if (in_array($config['id'], $convert_fields)) {
          $config['formatter']['type'] = 'layout_paragraphs';
          $config['formatter']['settings'] = ['view_mode' => 'default'];
          $component->setConfiguration($config);
          $save_node = TRUE;
        }
      }
    }
    if ($save_node) {
      $node->save();

      _stanford_profile_reset_node_changed_time($node, $changed_time);
    }
  }

  $sandbox['#finished'] = empty($sandbox['nids']) ? 1 : ($sandbox['count'] - count($sandbox['nids'])) / $sandbox['count'];
}

/**
 * Uninstall Stable theme.
 */
function stanford_profile_update_9100(&$sandbox) {
  try {
    \Drupal::service('theme_installer')->uninstall(['stable']);
  }
  catch (\Exception $e) {
    // Theme is already uninstalled.
  }
}

/**
 * Install menu_link module and configure the field.
 */
function stanford_profile_update_9101() {
  $entity_type_manager = \Drupal::entityTypeManager();

  \Drupal::service('module_installer')->install(['menu_link']);
  $entity_type_manager->getStorage('field_storage_config')
    ->create([
      'uuid' => '963caf4a-7a55-4ed6-961d-765ea7594192',
      'field_name' => 'field_menulink',
      'type' => 'menu_link',
      'entity_type' => 'node',
      'cardinality' => 1,
    ])->save();
  $field_config_storage = $entity_type_manager->getStorage('field_config');
  $bundles = [
    'stanford_page',
    'stanford_event_series',
    'stanford_person',
    'stanford_policy',
  ];
  foreach ($bundles as $bundle) {
    $field_config_storage->create([
      'entity_type' => 'node',
      'field_name' => 'field_menulink',
      'bundle' => $bundle,
      'label' => 'Menu Link',
    ])->save();
  }
  $menu_items = $entity_type_manager->getStorage('menu_link_content')
    ->loadByProperties(['menu_name' => 'main']);

  // Re-save all menu items to update their link uris.
  // @see \Drupal\stanford_profile_helper\EventSubscriber\EntityEventSubscriber::preSaveMenuLinkContent()
  foreach ($menu_items as $menu_item) {
    $menu_item->save();
  }
  drupal_flush_all_caches();
}

/**
 * Update menu links on nodes for the updated version of menu_link_weight.
 */
function stanford_profile_update_9102() {
  // Instantiate the path alias path processor because it doesn't get added in
  // this update hook.
  \Drupal::service('path_processor_manager')
    ->addOutbound(\Drupal::service('path_alias.path_processor'), 300);

  /** @var \Drupal\Core\Menu\MenuLinkTree $menu_link_tree */
  $menu_link_tree = \Drupal::service('menu.link_tree');
  $parameters = new MenuTreeParameters();

  $menu = $menu_link_tree->load('main', $parameters);
  _stanford_profile_fix_menu($menu);
}

/**
 * Re-run stanford_card update.
 */
function stanford_profile_update_9103(&$sandbox) {
  if ($field = FieldConfig::loadByName('paragraph', 'stanford_card', 'su_card_link_display')) {
    module_load_install('stanford_paragraph_card');
    stanford_paragraph_card_update_8001($sandbox);
    /** @var \Drupal\paragraphs\ParagraphsTypeInterface $paragraph_type */
    $paragraph_type = \Drupal::entityTypeManager()
      ->getStorage('paragraphs_type')
      ->load('stanford_card');
    $behaviors = $paragraph_type->get('behavior_plugins');
    $behaviors['su_card_styles'] = ['enabeld' => TRUE];
    $paragraph_type->set('behavior_plugins', $behaviors);
    $paragraph_type->save();
    $field->delete();
  }
  return;
  $ns = \Drupal::entityTypeManager()->getStorage('node');
  $ps = \Drupal::entityTypeManager()->getStorage('paragraph');
  $ids = $ns->getQuery()
    ->accessCheck(FALSE)
    ->condition('type', 'stanford_page')
    ->execute();
  foreach ($ns->loadMultiple($ids) as $node) {
    foreach ($node->get('su_page_components') as $item) {
      if ($p = $ps->load($item->getValue()['target_id'])) {
        $p->setParentEntity($node, 'su_page_components');
        $p->save();
      }
    }
  }
}

/**
 * Update menu links on nodes for the updated version of menu_link_weight.
 *
 * @param array $menu_items
 *   Menu items.
 * @param string|null $parent
 *   Parent menu id.
 */
function _stanford_profile_fix_menu(array $menu_items = [], string $parent = NULL): void {
  $node_storage = \Drupal::entityTypeManager()
    ->getStorage('node');
  /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
  $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
  $database = \Drupal::database();

  foreach ($menu_items as $id => $menu_item) {
    /** @var \Drupal\menu_link_content\Plugin\Menu\MenuLinkContent $link */
    $link = $menu_item->link;
    $url = $link->getUrlObject();

    try {
      if (
        $url->isRouted() &&
        $url->getRouteName() == 'entity.node.canonical'
      ) {
        $node_id = $link->getUrlObject()->getRouteParameters()['node'] ?? NULL;
        /** @var \Drupal\node\NodeInterface $node */
        $node = $node_storage->load($node_id);
        if (!$node->get('field_menulink')->isEmpty()) {
          throw new \Exception('Menu link already exists on node ' . $node->label());
        }

        $menu_field_data = [
          'menu_name' => $link->getMenuName(),
          'title' => $link->getTitle(),
          'description' => $link->getDescription(),
          'parent' => $parent,
          'weight' => $link->getweight(),
          'expanded' => $link->isExpanded(),
        ];
        $changed_time = $node->getChangedTime();
        $node->set('field_menulink', $menu_field_data)->save();
        $new_parent = 'menu_link_field:node_field_menulink_' . $node->uuid() . '_und';

        _stanford_profile_reset_node_changed_time($node, $changed_time);

        if ($menu_item->subtree) {
          _stanford_profile_fix_menu($menu_item->subtree, $new_parent);
        }

        if (!$link->isEnabled()) {
          $database->update('menu_tree')
            ->fields(['enabled' => 0])
            ->condition('id', $new_parent)
            ->execute();
        }

        // Update layout builder settings before deleting the link.
        _stanford_profile_update_menu_block($link->getPluginId(), $new_parent);
        $link->deleteLink();
        continue;
      }
    }
    catch (\Throwable $e) {
      \Drupal::logger('stanford_profile')
        ->error('Unable to update link %title. Error: %error', [
          '%title' => $link->getTitle(),
          '%error' => $e->getMessage(),
        ]);
    }

    if ($parent) {
      $link->updateLink(['parent' => $parent], TRUE);

      // Saving the link above, updates the entity, but it doesn't update the
      // menu tree. So we need to update the menu tree manually.
      $menu_link_manager->updateDefinition($link->getPluginId(), $link->getPluginDefinition(), FALSE);
    }

    if ($menu_item->subtree) {
      _stanford_profile_fix_menu($menu_item->subtree, $id);
    }
  }
}

/**
 * If the old menu link id is configured for menu block parent, update it.
 *
 * @param string $old_id
 *   Old menu link id.
 * @param string $new_id
 *   New menu link id.
 */
function _stanford_profile_update_menu_block(string $old_id, string $new_id): void {
  $node_storage = \Drupal::entityTypeManager()->getStorage('node');
  $nids = $node_storage->getQuery()
    ->accessCheck(FALSE)
    ->condition('layout_builder__layout', "%main:$old_id%", 'LIKE')
    ->execute();
  /** @var \Drupal\node\NodeInterface $node */
  foreach ($node_storage->loadMultiple($nids) as $node) {
    $save_node = FALSE;
    $changed_time = $node->getChangedTime();

    /** @var \Drupal\layout_builder\Field\LayoutSectionItemList $layout */
    $layout = $node->get('layout_builder__layout');
    foreach ($layout->getSections() as $section) {
      foreach ($section->getComponents() as $component) {
        $config = $component->get('configuration');
        if ($config['provider'] == 'menu_block' && $config['parent'] == "main:$old_id") {
          $config['parent'] = "main:$new_id";
          $component->setConfiguration($config);
          $save_node = TRUE;
        }
      }
    }
    if ($save_node) {
      $node->save();
      _stanford_profile_reset_node_changed_time($node, $changed_time);
    }
  }
}

/**
 * Update the node tables to reset the changed time.
 *
 * @param \Drupal\node\NodeInterface $node
 *   Node entity.
 * @param int $changed
 *   Changed time.
 */
function _stanford_profile_reset_node_changed_time(NodeInterface $node, int $changed) {
  $database = \Drupal::database();
  // Reset the changed time to the value before this process.
  $database->update('node_field_data')
    ->fields(['changed' => $changed])
    ->condition('nid', $node->id())
    ->execute();
  $database->update('node_field_revision')
    ->fields(['changed' => $changed])
    ->condition('vid', $node->getRevisionId())
    ->execute();
}

/**
 * Update configs 'stanford_profile_admin' with 'stanford_profile_admin_theme'.
 */
function stanford_profile_update_9104() {
  $config_factory = \Drupal::configFactory();
  foreach ($config_factory->listAll() as $config_name) {
    $config = $config_factory->getEditable($config_name);
    // Delete the admin theme blocks first.
    if (str_starts_with($config_name, 'block.block.stanford_profile_admin_')) {
      $config->delete();
      continue;
    }

    // Change the dependencies to the new theme name.
    if ($theme_dependencies = $config->get('dependencies.theme')) {
      $position = array_search('stanford_profile_admin', $theme_dependencies);
      if ($position !== FALSE) {
        $config->set("dependencies.theme.$position", 'stanford_profile_admin_theme')
          ->save(TRUE);
      }
    }
  }

  $core_extension = $config_factory->getEditable('core.extension');
  $core_extension->clear('theme.stanford_profile_admin')
    ->set('theme.stanford_profile_admin_theme', 0)
    ->save();

  $system_theme = $config_factory->getEditable('system.theme');
  if ($system_theme->get('admin') == 'stanford_profile_admin') {
    $system_theme->set('admin', 'stanford_profile_admin_theme')->save();
  }
}

/**
 * Remove data for paragraph rows.
 */
function stanford_profile_update_9105() {
  $tables = [
    'paragraph_row__su_page_components',
    'paragraph_row__su_pubs_components',
    'paragraph_row_revision__su_page_components',
    'paragraph_row_revision__su_pubs_components',
    'paragraph_rows_field_revision',
    'paragraph_rows_item',
    'paragraph_rows_item_field_data',
    'paragraph_rows_revision',
  ];
  foreach ($tables as $table) {
    \Drupal::database()->truncate($table)->execute();
  }
}