Skip to content
Snippets Groups Projects
uw_cfg_common.install 29.9 KiB
Newer Older
Liam Morland's avatar
Liam Morland committed
<?php

/**
 * @file
 * Install, update and uninstall for Configuration of all common WCMS.
 */

use Drupal\Core\Config\FileStorage;
use Drupal\field\Entity\FieldConfig;
use Drupal\node\Entity\Node;
use Drupal\taxonomy\Entity\Term;
use Drupal\uw_cfg_common\UwPermissions\UwPermissions;
use Drupal\uw_cfg_common\UwRoles\UwRoles;
use Drupal\webform\WebformInterface;
Liam Morland's avatar
Liam Morland committed

/**
 * Implements hook_install().
 */
function uw_cfg_common_install() {
  // ISTWCMS-5865: this the attempt to fix features for our build.
  // Moving the actual installing of workflows to here, so that
  // we can include workflows as a dependency in our modules and
  // that it will allow new site installs.
  $name = 'workflows.workflow.uw_workflow';
  $path = \Drupal::service('extension.list.module')->getPath('uw_cfg_common') . '/config/custom/';
  $source = new FileStorage($path);
  $active_storage = \Drupal::service('config.storage');
  $active_storage->write($name, $source->read($name));

  // Get the role ids for UW roles.
  $uw_rids = UwRoles::getUwRoleIds();

  // Step through each of the rids and create
  // role and set permissions.
  foreach ($uw_rids as $uw_rid) {

    // Create the role.
    $role = Role::create(
      [
        'id' => $uw_rid,
        'label' => UwRoles::getUwRoleLabel($uw_rid),
      ]
    );
    $role->save();

    // Get the info about the role.
    $uw_role = UwRoles::getUwRole($uw_rid);

    // Set the permissions for the role.
    UwRoles::setUwPermissions($uw_role);
  }

  // Get the role ids for Drupal roles.
  $drupal_rids = UwRoles::getDrupalRoleIds();

  // Step through each of the Drupal roles and
  // set the permissions.
  foreach ($drupal_rids as $drupal_rid) {

    // Get the info about the role.
    $uw_role = UwRoles::getUwRole($drupal_rid);

    // Set the permissions for the role.
    UwRoles::setUwPermissions($uw_role);
  }
  // Build the access permissions array.
  $module_handler = \Drupal::service('module_handler');
  $module_path = $module_handler->getModule('uw_cfg_common')->getPath();
  $permissions_to_process = Yaml::parseFile($module_path . '/src/UwRoles/access_content_permissions.yml');
  UwPermissions::grantRevoke($permissions_to_process, 'grant');

  // Add terms to the vocabulary 'uw_vocab_audience'.
  $terms = [
    'Current students' => [
      'Current undergraduate students',
      'Current graduate students',
    ],
    'Future students' => [
      'Future undergraduate students',
      'Future graduate students',
    ],
    'Faculty' => 'Faculty',
    'Staff' => 'Staff',
    'Alumni' => 'Alumni',
    'Parents' => 'Parents',
    'Donors | Friends | Supporters' => 'Donors | Friends | Supporters',
    'Employers' => 'Employers',
    'International' => 'International',
    'Media' => 'Media',
  ];

  $weight = 0;
  foreach ($terms as $key => $term) {
    if (is_array($term)) {
      $parent = _uw_cfg_common_create_term($key, 'uw_vocab_audience', $weight, []);
      foreach ($term as $child) {
        _uw_cfg_common_create_term($child, 'uw_vocab_audience', $childweight, [$parent]);
        $childweight++;
      }
    }
    else {
      _uw_cfg_common_create_term($term, 'uw_vocab_audience', $weight, []);
    }
  }
}

/**
 * @file
 * Contains various helper functions.
 */

/**
 * Helper function to create a taxonomy term programmatically.
 *
 * @code
 * // Create top level term
 * $term_id = _nodemaker_term_create('My Term', 'my_vocab', 0, []);
 *
 * // Create term with parent term with an id of 999
 * $term_id = _nodemaker_term_create('My Term', 'my_vocab', 0, [999]);
 * @endcode
 *
 * @param string $taxonomy_name
 * @param string $vocab_machine_name
 *   - System id of the vocabulary term will be added to.
 * @param string|int $weight
 *   - Taxonomy term weight.
 * @param array $parent_tid
 *   - Array of term ids to be assigned as parent.
 *
 * @return int|null
 *   - Returns the term id of the created term on success, null on failure.
 *
 * @throws \Drupal\Core\Entity\EntityStorageException
 */
function _uw_cfg_common_create_term($taxonomy_name, $vocab_machine_name, $weight, array $parent_tid = []) {

  // Create the taxonomy term.
  $new_term = Term::create([
    'name' => $taxonomy_name,
    'vid' => $vocab_machine_name,
    'parent' => $parent_tid,
    'weight' => $weight,
  ]);

  // Save the taxonomy term.
  $new_term->save();

  // Return the taxonomy term id.
  return $new_term->id();
Liam Morland's avatar
Liam Morland committed
}
/**
 * Implements hook_update_dependencies().
 */
function uw_cfg_common_update_dependencies() {
  $dependencies['uw_cfg_common'][8103] = [
    'uw_sites_all' => 8105,
  ];

  $dependencies['uw_cfg_common'][9108] = [
    'uw_ct_service' => 9101,
  ];

Liam Morland's avatar
Liam Morland committed
/**
 * Implements hook_update_N().
 */

 * Update listing blocks items per page when needed.
 * For listing blocks items per page, when default settings were used,
 * change to the original default number of items.
  // Block ids that need to be changed, and what the original default was.
  // For some reason, we didn't originally use the same number for everything.
    'views_block:uw_view_blogs-blogs_listing_block' => 5,
    'views_block:uw_view_events-events_listing_block' => 10,
    'views_block:uw_view_news_items-news_items_listing_block' => 10,
  $nodes = Node::loadMultiple();
  // Step through each node and set any that were using the default setting
  // to the number that was the default before this change.
  foreach ($nodes as $node) {

    // Flag to save the node, have this to save processing
    // time if we don't need to save the node after the checks.
    $save_node_flag = FALSE;

    // Load the layout and sections.
    $layout = $node->get('layout_builder__layout');
    $sections = $layout->getSections();

    // Step through each of the sections.
    foreach ($sections as $section) {

      // Load the components for the section.
      $components = $section->getComponents();

      // Step through each of the components.
      foreach ($components as $component) {

        // If this component is one that needs to be changed,
        // then check for setting and change if required.
        if (in_array($component->getPluginId(), array_keys($block_ids))) {

          // Load the config for the block.
          $configurations = $component->get('configuration');

          // If the config is set to "none", it needs to be changed to
          // be set to the number that was the old default value.
          if ($configurations['items_per_page'] == 'none') {
            // Change the config and save the component.
            $configurations['items_per_page'] = $block_ids[$component->getPluginId()];
            $component->setConfiguration($configurations);

            // Set the save node flag so that we know to
            // save this node as the last step in the loop.
            $save_node_flag = TRUE;
          }
        }
      }

      // If we need to save the node, then save it.
      if ($save_node_flag) {
        $node->save();
      }
    }

    // Load all the revisions for the node.
    $vids = \Drupal::service('entity_type.manager')->getStorage('node')->revisionIds($node);

    // Step through each revision, and check if we have to
    // change the settings for the listing blocks.
    foreach ($vids as $vid) {

      // Flag to see if we have to save the revision.
      $save_revision_flag = FALSE;

      // Load the revision node.
      $revision_node = \Drupal::service('entity_type.manager')->getStorage('node')->loadRevision($vid);

      // Comments from here down are the same as above.
      $layout = $revision_node->get('layout_builder__layout');
      $sections = $layout->getSections();

      foreach ($sections as $section) {

        $components = $section->getComponents();

        foreach ($components as $component) {

          if (in_array($component->getPluginId(), $block_ids)) {

            $configurations = $component->get('configuration');

            if (
              $configurations['items_per_page'] == 'none' ||
              $configurations['items_per_page'] == '5'
            ) {

              $configurations['items_per_page'] = '3';
              $component->setConfiguration($configurations);
              $save_revision_flag = TRUE;
            }
          }
        }
      }

      if ($save_revision_flag) {
        $revision_node->save();
      }
    }
  }
}

/**
 * Set draggable views permissions, since cd-update doesn't do it reliably.
 */
function uw_cfg_common_update_8102() {
  $roles = [
    'uw_role_content_author',
    'uw_role_content_editor',
    'uw_role_form_editor',
    'uw_role_form_results_access',
    'uw_role_site_manager',
    'uw_role_site_owner',
  ];
  foreach ($roles as $role_name) {
    $role_object = Role::load($role_name);
    $role_object->grantPermission('access draggableviews');
    $role_object->save();
  }
}

/**
 * Load config and assigns permissions to roles.
 *
 * Load quick_node_clone config.
 */
function uw_cfg_common_update_8103() {

  // Load config that is not being set properly by config distro update.
  $module_path = \Drupal::service('extension.list.module')->getPath('uw_cfg_common');
  $config_path = $module_path . '/config/install';
  $source = new FileStorage($config_path);
  $config_storage = \Drupal::service('config.storage');
  $config_storage->write('quick_node_clone.settings', $source->read('quick_node_clone.settings'));

  // List of permissions needed to be applied to roles.
  $permissions = [
    'clone uw_ct_blog content',
    'clone uw_ct_catalog_item content',
    'clone uw_ct_contact content',
    'clone uw_ct_event content',
    'clone uw_ct_news_item content',
    'clone uw_ct_profile content',
    'clone uw_ct_sidebar content',
    'clone uw_ct_web_page content',
  ];

  // Roles that require updated permissions.
  $role_ids = [
    'uw_role_site_manager',
    'uw_role_content_editor',
    'uw_role_content_author',
  ];

  $roles = Role::loadMultiple($role_ids);

  // Grant all all roles.
  foreach ($permissions as $permission) {
    $roles['uw_role_site_manager']->grantPermission($permission);
    $roles['uw_role_content_editor']->grantPermission($permission);
    $roles['uw_role_content_author']->grantPermission($permission);
  }

  // Save role with new permissions.
  $roles['uw_role_site_manager']->save();
  $roles['uw_role_content_editor']->save();
  $roles['uw_role_content_author']->save();

}

 * Give default access to Webforms that have no access to create submissions.
 */
function uw_cfg_common_update_8104() {
  $counter = 0;

  $webforms = \Drupal::entityTypeManager()->getStorage('webform')->loadMultiple();
  foreach ($webforms as $webform) {
    $access = $webform->getAccessRules();
    if (empty($access['create']['roles'])) {
      $access['create']['roles'] = [
        'anonymous',
        'authenticated',
      ];
      $webform->setAccessRules($access);
      $webform->save();
      $counter++;
    }
  }

  return t('Set default access for @counter Webforms.', ['@counter' => $counter]);
}

/**
 * Update the fields required for new media section.
 */
function uw_cfg_common_update_9101() {

  // The content types to get updated.
  $node_types = [
    'uw_ct_blog',
    'uw_ct_event',
    'uw_ct_news_item',
  ];

  // We need to a feature revert first, so tha the fields for
  // type of media are created.
  // Reverting uw_cfg_common first so that the fields get created.
  \Drupal::service('uw_cfg_common.features')->import(['uw_cfg_common']);

  // Revert the rest of the content types.
  \Drupal::service('uw_cfg_common.features')->import($node_types);

  // Step through each of the content types and update the field.
  foreach ($node_types as $node_type) {

    // Get all the nids of the content type.
    $query = \Drupal::service('entity_type.manager')->getStorage('node')->getQuery();
    $nids = $query
      ->condition('type', $node_type)
      ->accessCheck(FALSE)
      ->execute();

    // Step through each of the nids, get the node and check
    // if we have to update the field.
    foreach ($nids as $nid) {

      // Load the node.
      $node = \Drupal::service('entity_type.manager')->getStorage('node')->load($nid);

      // If there is a hero image, update the type of media field,
      // then save the node.
      if ($node->field_uw_hero_image->entity) {
        $node->set("field_uw_type_of_media", 'image');
        $node->save();
      }
    }
  }
}

/**
 * Set all Webforms to use the access denied page.
 */
function uw_cfg_common_update_9102() {
  $webforms = \Drupal::entityTypeManager()->getStorage('webform')->loadMultiple();
  foreach ($webforms as $webform) {
    // This is set as the default in uw_cfg_common_webform_create().
    $webform->setSetting('form_access_denied', WebformInterface::ACCESS_DENIED_PAGE);
    $webform->save();
  }
}

/**
 * Add Private content viewer role for the existing site.
 */
function uw_cfg_common_update_9103() {
  Role::create([
    'id' => 'uw_role_private_content_viewer',
    'label' => 'Private content viewer',
  ])->save();
}
Igor Biki's avatar
Igor Biki committed

/**
 * Removes missing blocks from temp storage and saved nodes (revisions too).
 */
function uw_cfg_common_update_9104(&$sandbox) {
  $service = \Drupal::service('uw_cfg_common.missing_blocks');
  $service->removeMissingBlocksFromUnsaved();
  $service->removeMissingBlocksFromSaved();
}

/**
 * Feature revert for workflows.
 */
function uw_cfg_common_update_9105(&$sandbox) {
  $name = 'workflows.workflow.uw_workflow';
  $path = \Drupal::service('extension.list.module')->getPath('uw_cfg_common') . '/config/custom/';
  $source = new FileStorage($path);
  $active_storage = \Drupal::service('config.storage');
  $active_storage->write($name, $source->read($name));
}

/**
 * Add new fields for banners above.
 */
function uw_cfg_common_update_9106(&$sandbox) {

  // The database service.
  $database = \Drupal::database();

  // The tables to be used for fields to get and remove.
  $tables = [
    'node__field_uw_type_of_media',
    'node_revision__field_uw_type_of_media',
    'node__field_uw_hero_image',
    'node_revision__field_uw_hero_image',
  ];

  // Setting up an empty array so that we do not get
  // undefined index or unknown variable error.
  $node_data = [];

  // Step through each of the tables and get the data,
  // then truncate them.  We need to truncate the table
  // so that we are able to modify the fields, if there
  // is data in these tables, Drupal throws an error about
  // data already existing in the fields.  We will insert
  // the data back into the tables after everything is
  // completed.
  foreach ($tables as $table) {

    // Get the rows in the table.
    $values = $database->select($table, 'n')
      ->fields('n')
      ->execute()
      ->fetchAll();

    // Step through each of the rows and add to variable.
    foreach ($values as $value) {

      // Add to the variable and cast to an array so that
      // we are not using an object, just makes it easier
      // to work with when inserting these rows back
      // into the database.
      $node_data[$table][] = (array) $value;
    }

    // Truncate the table.
    $database->truncate($table)->execute();
  }

  // The content types that are not getting any changes.
  $cts_not_to_install = [
    'uw_ct_sidebar',
    'uw_ct_site_footer',
    'uw_ct_expand_collapse_group',
  ];

  // The content types with media already in it (hero image).
  $cts_with_media = [
    'uw_ct_blog',
    'uw_ct_event',
    'uw_ct_news_item',
  ];

  // Get all the node types.
  $node_types = \Drupal::entityTypeManager()->getStorage('node_type')->loadMultiple();

  // Step through each node type and get the path to
  // the module and the machine name.
  foreach ($node_types as $node_type) {

    // Get the id from the node type.
    $id = $node_type->id();

    // Ensure we are only getting the node type
    // that need updating.
    if (!in_array($id, $cts_not_to_install)) {

      // Catalogs and opportunities have different paths
      // and ids, so setup the content types array with
      // the correct info.
      if ($id == 'uw_ct_catalog_item') {
        $content_types['uw_ct_catalog'] = $id;
      }
      elseif ($id == 'uw_ct_opportunity') {
        $content_types['uw_ct_opportunities'] = $id;
        $content_types[$id] = $id;
      }
    }
  }

  // Get the type of media field that we need to udpate.
  $type_of_media = current(\Drupal::entityTypeManager()->getStorage('field_storage_config')->loadByProperties(['id' => 'node.field_uw_type_of_media']));

  // Get the type of media settings.
  $settings = $type_of_media->getSettings();

  // Update the settings to remove the allowed values and
  // add the allowed values function.
  $settings['allowed_values'] = [];
  $settings['allowed_values_function'] = '_uw_cfg_common_allowed_media_types';

  // Set the update settings.
  $type_of_media->setSettings($settings);

  // Save the field.
  $type_of_media->save();

  // The names of the fields we need to install.
  $names = [
    'field.storage.node.field_uw_banner',
    'field.storage.node.field_uw_media_width',
    'field.storage.node.field_uw_slide_speed',
    'field.storage.node.field_uw_transition_speed',
    'field.storage.node.field_uw_autoplay',
    'field.storage.node.field_uw_text_overlay_style',
  ];

  // Get the path to cfg common config install directory.
  $path = \Drupal::service('extension.list.module')->getPath('uw_cfg_common') . '/config/install/';
  $config_dir = new FileStorage($path);

  // Step through each of the field names and install them.
  foreach ($names as $name) {

    // Get the config from the yml file into an array.
    $config_record = $config_dir->read($name);

    // Get the entity type.
    $entity_type = \Drupal::service('config.manager')->getEntityTypeIdByName($name);

    // Get the storage.
    $storage = \Drupal::entityTypeManager()->getStorage($entity_type);

    // Create the new field from the converted yml.
    $field = $storage->createFromStorageRecord($config_record);

    // Save the new field.
    $field->save();
  }

  // Step through each of the content types and install the fields,
  // and also setup default values for the fields.
  foreach ($content_types as $path => $id) {

    // Get the path to the content type.
    $path = \Drupal::service('extension.list.module')->getPath($path) . '/config/install/';
    $config_dir = new FileStorage($path);

    // The names of the fields to install.
    $names = [
      'field.field.node.' . $id . '.field_uw_banner',
      'field.field.node.' . $id . '.field_uw_type_of_media',
      'field.field.node.' . $id . '.field_uw_media_width',
      'field.field.node.' . $id . '.field_uw_slide_speed',
      'field.field.node.' . $id . '.field_uw_autoplay',
      'field.field.node.' . $id . '.field_uw_text_overlay_style',
      'field.field.node.' . $id . '.field_uw_transition_speed',
    ];

    // Step through each of the fields and install them.
    foreach ($names as $name) {

      // Get the config from the yml into an array.
      $config_record = $config_dir->read($name);

      // If the field config is not install, install it.
      if (!FieldConfig::loadByName(
        $config_record['entity_type'],
        $config_record['bundle'],
        $config_record['field_name'])
      ) {
        FieldConfig::create($config_record)->save();
      }
    }

    // If there is no media yet on the content type,
    // then install the type of hero image field.
    if (!in_array($id, $cts_with_media)) {

      // Name of the hero image field.
      $name = 'field.field.node.' . $id . '.field_uw_hero_image';

      // Get the config from the yml into an array.
      $config_record = $config_dir->read($name);

      // If the field config is not install, install it.
      if (!FieldConfig::loadByName($config_record['entity_type'], $config_record['bundle'], $config_record['field_name'])) {
        FieldConfig::create($config_record)->save();
      }
    }

    // Get all the nodes of the content type.
    $nodes = \Drupal::entityTypeManager()->getStorage('node')->loadByProperties(['type' => $id]);

    // Step through each of the nodes and set the default
    // values of the fields.
    foreach ($nodes as $node) {

      // Set default values for banners.
      $node->field_uw_banner = NULL;
      $node->field_uw_media_width = 'uw_lbs_full_width';
      $node->field_uw_slide_speed = 7000;
      $node->field_uw_transition_speed = 400;
      $node->field_uw_autoplay = TRUE;
      $node->field_uw_text_overlay_style = 'full-width';

      // If the content type does not have media yet,
      // set the default value for type of media.
      if (!in_array($id, $cts_with_media)) {
        $node->field_uw_type_of_media = NULL;
      }

      // Save the node.
      $node->save();
    }
  }
  // Ensure that we have some data to put back in the DB.
  if (!empty($node_data)) {
    // Step through all the tables and insert back into
    // the database.
    foreach ($node_data as $table => $data) {
      // Get all the rows from the table.
      foreach ($data as $field_data) {
        // Reset the fields array, so we are working with
        // a blank array to insert.
        $fields = [];
        // Step through all the entries in the row and add
        // to the fields array, this makes it much easier to
        // do one insert command.
        foreach ($field_data as $key => $value) {
          $fields[$key] = $value;
        }

        // Insert the row into the database.
        $database->insert($table)
          ->fields($fields)
          ->execute();
      }

/**
 * Swap the order of content author and editor roles.
 */
function uw_cfg_common_update_9107(&$sandbox) {
  // The original weight of content editor role is 5.
  // The original weight of content author role is 4.
  $role_ids = [
    'uw_role_content_editor' => 4,
    'uw_role_content_author' => 5,
  ];
  // Set new weight of content editor role as 4.
  // Set new weight of content author role as 5.
  foreach ($role_ids as $role_id => $weight) {
    $role = Role::load($role_id);
    $role->setWeight($weight);
    $role->save();
}

/**
 * Add new path field for most nodes.
 */
function uw_cfg_common_update_9108(&$sandbox) {

  // The query.
  $query = \Drupal::entityQuery('node');

  // The or condition for the query.
  $group = $query->orConditionGroup();

  // The number of nodes per batch.
  $nodes_per_batch = 50;

  // Get the content types to batch.
  $content_types = _uw_get_node_types();

  // If there is no batching, set it up.
  if (!isset($sandbox['total'])) {
    \Drupal::logger('uw_cfg_common')->info('9108 - Setting counters');
    $sandbox['total'] = 0;
    $sandbox['processed'] = 0;
    $sandbox['#finished'] = 0;
    $sandbox['pre_batch'] = FALSE;
  }

  // If we have not run the batch, run the stuff requried before
  // we actually run the batch.
  if (!$sandbox['pre_batch']) {

    \Drupal::logger('uw_cfg_common')->info('9108 - running pre_batch');

    // Set the field storage config.
    _uw_set_fieldable_path_storage_config();

    // Step through each of conent types and add the group or.
    foreach ($content_types as $content_type) {
      // Add the content type to the or condition.
      $group->condition('type', $content_type, '=');
    }

    // Get all the nids.
    $nids = $query->condition($group)
      ->accessCheck(FALSE)
      ->execute();

    // Set the or condition into the sandbox.
    $sandbox['group'] = $group;

    // Set the total number of nids into the sandbox.
    $sandbox['total'] = count($nids);

    // To prevent repeating the process on next batch.
    $sandbox['pre_batch'] = TRUE;
  }

  \Drupal::logger('uw_cfg_common')->info('9108 - starting fieldable path node');

  // Set the field path in the node for each content type.
  _uw_set_feildable_path_node($content_types);

  \Drupal::logger('uw_cfg_common')->info('9108 - ending fieldable path node');

  // Get the nids for the content type. We do it this
  // way so that we do not load all the node objects
  // at once, which was causing memory errors on
  // Pantheon. Bypassing access check. Work in batches of 50.
  $nids = \Drupal::entityQuery('node')
    ->condition($sandbox['group'])
    ->accessCheck(FALSE)
    ->range($sandbox['processed'], $nodes_per_batch)
    ->execute();

  \Drupal::logger('uw_cfg_common')->info('9108 - starting node loop - ' . count($nids) . ' - ' . $sandbox['processed'] . ' - ' . $nodes_per_batch);

  // Step through each of the nids and perform the
  // update tasks for fieldable path.
  foreach ($nids as $nid) {

    // Load the actual node, this way we are only
    // loading one full node object at a time.
    $entity = \Drupal::entityTypeManager()
      ->getStorage('node')
      ->load($nid);

    // If there is no path, skip this node.
    if (!$entity->hasField('path')) {
      return;
    }

    // Load entity's internal path (i.e. /node/2).
    $internal_path = $entity->toUrl()->getInternalPath();
    $alias = \Drupal::service('path_alias.manager')
      ->getAliasByPath('/' . $internal_path);

    // Update the fieldable path field.
    \Drupal::service('fieldable_path.controller')
      ->updateFieldablePath($entity, ['alias' => $alias]);
  }

  \Drupal::logger('uw_cfg_common')->info('9108 - ending node loop');

  // Update the number of nids processed.
  $sandbox['processed'] += count($nids);

  // Set the message to display.
  $message = t(
    'Processing nodes of - @p/@t.',
    [
      '@p' => $sandbox['processed'],
      '@t' => $sandbox['total']
    ]
  );

  // If we are done, then complete the batching.
  if ($sandbox['processed'] >= $sandbox['total']) {
    \Drupal::logger('uw_cfg_common')->info('9108 - all nodes proccessed');
    $sandbox['#finished'] = 1;
    return $message;
  }

  // Update the finished, when done processed / total will be 1.
  $sandbox['#finished'] = ($sandbox['processed'] / $sandbox['total']);

  return $message;
}

/**
 * Function to set the fieldable path storage config.
 *
 * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
 * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
 */
function _uw_set_fieldable_path_storage_config() {

  // The modules to install.
  $modules = [
    'fieldable_path',
    'jsonapi',
    'jsonapi_extras',
  ];

  // Install the modules.
  \Drupal::service('module_installer')->install($modules);

  $module_path = Drupal::service('extension.list.module')
    ->getPath('uw_cfg_common');

  // Get the config path to uw_cfg_common.
  $config_path = $module_path . '/config/install';

  // Get a new file source object to uw_cfg_common config path.
  $source = new FileStorage($config_path);

  // The config storage service.
  $config_storage = \Drupal::service('config.storage');

  // Write the new storage of jsonapi_extras settings.  We need this
  // since when we do a feature revert, the database is not setup
  // correctly causing a serialization error.  This will alleviate
  // that error.
  $config_storage->write(
    'jsonapi_extras.settings',
    $source->read('jsonapi_extras.settings')
  );

  // The field storage name.
  $name = 'field.storage.node.field_path';

  // Get the path to cfg common config install directory.
  $path = \Drupal::service('extension.list.module')
    ->getPath('uw_cfg_common') . '/config/install/';
  $config_dir = new FileStorage($path);

  // Get the config from the yml file into an array.
  $config_record = $config_dir->read($name);

  // Get the entity type.
  $entity_type = \Drupal::service('config.manager')
    ->getEntityTypeIdByName($name);

  // Get the storage.
  $storage = \Drupal::entityTypeManager()->getStorage($entity_type);

  // Create the new field from the converted yml.
  $field = $storage->createFromStorageRecord($config_record);

  // Save the new field.
  $field->save();
}

/**
 * Function to get the uw content types.
 *
 * @return array
 *   The array of content types.
 *
 * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
 * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
 */
function _uw_get_node_types() {

  // The content types that are not getting any changes.
  $cts_not_to_install = [
    'uw_ct_sidebar',
    'uw_ct_site_footer',
    'uw_ct_expand_collapse_group',
  ];

  // Get all the node types.
  $node_types = \Drupal::entityTypeManager()
    ->getStorage('node_type')
    ->loadMultiple();

  // Step through each node type and get the path to
  // the module and the machine name.
  foreach ($node_types as $node_type) {

    // Get the id from the node type.
    $id = $node_type->id();

    // Ensure we are only getting the node type
    // that need updating.
    if (!in_array($id, $cts_not_to_install)) {

      // Catalogs and opportunities have different paths
      // and ids, so setup the content types array with
      // the correct info.
      if ($id === 'uw_ct_catalog_item') {
      elseif ($id === 'uw_ct_opportunity') {
        $content_types['uw_ct_opportunities'] = $id;
      }
      else {
        $content_types[$id] = $id;
      }
    }
  }

  return $content_types;
}

/**
 * Function to set the fieldable on a node.
 *
 * @param array $content_types
 *   The array of content types.
 *
 * @throws \Drupal\Core\Entity\EntityStorageException
 */
function _uw_set_feildable_path_node(array $content_types) {

  // Step through each of the content types and install the fields,
  // and also setup default values for the fields.
  foreach ($content_types as $path => $content_type) {

    // Get the path to the content type.
    $path = \Drupal::service('extension.list.module')->getPath($path) . '/config/install/';
    $config_dir = new FileStorage($path);