SU-HKKU/cardinal_service_profile

View on GitHub
cardinal_service_profile.inc

Summary

Maintainability
Test Coverage
<?php

/**
 * @file
 * cardinal_service_profile.inc
 */

use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\Display\EntityFormDisplayInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\field\FieldConfigInterface;
use Drupal\node\NodeInterface;
use Drupal\views\ViewExecutable;
use Drupal\pathauto\PathautoPatternInterface;

/**
 * Implements hook_pathauto_pattern_alter().
 */
function cardinal_service_profile_pathauto_pattern_alter(PathautoPatternInterface $pattern, array $context) {
  // Change the path auto pattern if the page is a resource.
  if ($context['module'] == 'node' && $context['bundle'] == 'stanford_page') {
    /** @var \Drupal\node\NodeInterface $node */
    $node = $context['data']['node'];
    if ($node->get('su_page_resource_dimension')->count()) {
      $pattern->setPattern('/resources/[node:title]');
    }
  }
}

/**
 * Implements hook_ENTITY_TYPE_presave().
 */
function cardinal_service_profile_node_presave(NodeInterface $node) {
  if ($node->bundle() == 'su_spotlight' && $node->get('su_spotlight_student_name')
      ->getString() === $node->label()) {
    $node->set('su_spotlight_student_name', NULL);
    return;
  }

  if ($node->bundle() != 'su_opportunity' || !$node->hasField('su_opp_application_deadline')) {
    return;
  }

  $deadline_date = $node->get('su_opp_application_deadline')->getString();
  if (empty($deadline_date)) {
    return;
  }

  // Compare the month and day of the deadline field value to taxonomy terms to
  // find out what term has the applicable date range.
  $terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')
    ->loadByProperties(['vid' => 'su_opportunity_deadline']);

  /** @var \Drupal\taxonomy\TermInterface $term */
  foreach ($terms as $term) {
    $deadline_range = $term->get('su_opp_deadline_date')->getValue();
    // The term doesn't have the field value set, skip it.
    if (empty($deadline_range[0]['value'])) {
      continue;
    }

    // This term is configured for the range surrounding the deadline date field
    // so we use that term id as the deadline term.
    if (_cardinal_service_profile_between_dates($deadline_range[0]['value'], $deadline_range[0]['end_value'], $deadline_date)) {
      $node->set('su_opp_deadline_time', $term->id());
      return;
    }

  }

}

/**
 * Check if a given date is between two other dates in terms of month and day.
 *
 * Compare only the month and day of the string. We don't need to check anything
 * with the year, hours, or minutes.
 *
 * @param string $from_date
 *   Date string in the form of 2020-01-30.
 * @param string $to_date
 *   Date string in the form of 2020-01-30.
 * @param string $date
 *   Date string in the form of 2020-01-30T12:35:11.
 *
 * @return bool
 *   True if the date is between.
 */
function _cardinal_service_profile_between_dates($from_date, $to_date, $date) {
  $date = (int) date('md', strtotime($date));

  list(, $from_month, $from_day) = explode('-', $from_date);
  list(, $to_month, $to_day) = explode('-', $to_date);

  $from = (int) "$from_month$from_day";
  $to = (int) "$to_month$to_day";

  if ($from > $to) {
    return $date >= $from || $date <= $to;
  }
  return $date >= $from && $date <= $to;
}

/**
 * Implements hook_preprocess_hook().
 */
function cardinal_service_profile_preprocess_flag(&$variables) {
  if (\Drupal::currentUser()->isAuthenticated()) {
    return;
  }

  unset($variables['attributes']['class']);
  $current_url = \Drupal::request()->getRequestUri();
  $separator = strpos($current_url, '?') !== FALSE ? '&' : '?';
  $current_url .= $separator . 'flag_type=' . $variables['flaggable']->getEntityTypeId() . '&flag_id=' . $variables['flaggable']->id() . '&flag=' . $variables['flag']->id();
  $current_url = urlencode($current_url);
  $variables['attributes']['href'] = "/saml_login?destination=$current_url";
}

/**
 * Implements hook_user_login().
 */
function cardinal_service_profile_user_login($account) {
  $request_queries = \Drupal::request()->query;
  // User logged in without a destination parameter, nothing to do.
  if (!$request_queries->has('destination')) {
    return;
  }

  // The destination exists, but it doesn't contain any query parameters that
  // might be flag params, nothing to do.
  $url = parse_url($request_queries->get('destination'));
  if (empty($url['query'])) {
    return;
  }

  // The destination query doesn't contain all the appropriate parameters,
  // nothing to do.
  parse_str($url['query'], $params);
  if (!(isset($params['flag_type']) && isset($params['flag_id']) && isset($params['flag']))) {
    return;
  }

  $flag = [
    'flag_id' => $params['flag'],
    'entity_type' => $params['flag_type'],
    'entity_id' => $params['flag_id'],
    'uid' => $account->id(),
  ];

  // Look for an existing flag for the current user. If a flag entity exists,
  // the user has already saved it. If the flag entity doesn't exist, create it
  // so it's saved for the user.
  $flagging_storage = \Drupal::entityTypeManager()->getStorage('flagging');
  if (empty($flagging_storage->loadByProperties($flag))) {
    $flagging_storage->create($flag)->save();
  }
}

/**
 * Implements hook_views_pre_build().
 */
function cardinal_service_profile_views_pre_build(ViewExecutable $view) {
  // On the user dashboard, add a contextual argument to the news view to
  // display the announcement news items.
  if (
    $view->id() == 'stanford_news' &&
    \Drupal::routeMatch()->getRouteName() == 'entity.user.canonical'
  ) {
    $terms = \Drupal::entityTypeManager()
      ->getStorage('taxonomy_term')
      ->loadByProperties(['name' => 'Announcements']);
    $view->setArguments(array_keys($terms));
    $view->empty = [];
  }
}

/**
 * Implements hook_entity_form_display_alter().
 */
function cardinal_service_profile_entity_form_display_alter(EntityFormDisplayInterface &$form_display, array $context) {
  $route_name = \Drupal::routeMatch()->getRouteName();
  // Make sure we are editing the form only for editing users.
  if (
    \Drupal::currentUser()->hasPermission('administer account settings') ||
    !isset($context['entity_type']) ||
    $context['entity_type'] !== 'user' ||
    $route_name !== 'entity.user.edit_form'
  ) {
    return;
  }

  /** @var \Drupal\Core\Entity\EntityDisplayRepository $entity_display_repo */
  $entity_display_repo = \Drupal::service('entity_display.repository');
  $form_display = $entity_display_repo->getFormDisplay($context['entity_type'], $context['bundle'], 'authenticated_edit') ?: $form_display;
}

/**
 * Implements hook_ui_patterns_info_alter().
 */
function cardinal_service_profile_ui_patterns_info_alter(array &$definitions) {
  if (isset($definitions['yaml:quote'])) {
    $definitions['yaml:quote']->setField('content', 'Additional Content');
    $definitions['yaml:quote']->setField('link', 'Link to More Content');
  }
}

/**
 * Implements hook_react_paragraphs_form_field_data_alter().
 */
function cardinal_service_profile_react_paragraphs_form_field_data_alter(array &$info, array $field_element, FieldConfigInterface $field_config) {
  if ($field_config->getName() == 'su_opp_list_view') {
    $good_displays = ['context_filtered_opps'];
    foreach ($info['displays']['su_opportunities'] as $key => $display) {
      if (!in_array($display['value'], $good_displays)) {
        unset($info['displays']['su_opportunities'][$key]);
      }
    }
    $info['displays']['su_opportunities'] = array_values($info['displays']['su_opportunities']);
  }

  if ($field_config->getName() == 'su_resource_list') {
    $good_displays = [
      '3_related',
      'all_list',
      'audience',
      'audience_program_filtered',
      'program_filtered',
    ];
    foreach ($info['displays']['cs_resources'] as $key => $display) {
      if (!in_array($display['value'], $good_displays)) {
        unset($info['displays']['cs_resources'][$key]);
      }
    }
    $info['displays']['cs_resources'] = array_values($info['displays']['cs_resources']);
  }
}

/**
 * Implements hook_form_alter().
 */
function cardinal_service_profile_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  if ($form_id == 'node_su_opportunity_edit_form') {
    /** @var \Drupal\node\NodeForm $form_object */
    $form_object = $form_state->getBuildInfo()['callback_object'];
    $entity = $form_object->getEntity();

    // The current node was imported via migration, present the user with a
    // message and a link to that profile.
    if (_cardinal_service_node_imported($entity)) {
      \Drupal::messenger()
        ->addWarning(t('Some fields can not be edited since they contain imported data. They are not visible here.'));
    }
  }
}

/**
 * Implements hook_entity_field_access().
 */
function cardinal_service_profile_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
  $route_match = \Drupal::routeMatch();

  // When the user is viwing the node detail page, hide some of the fields
  // based on other fields having some data.
  if (_cardinal_service_profile_viewing_node_page($operation, $items)) {
    switch ($field_definition->getName()) {
      case 'su_spotlight_quote':
        if ($items->getEntity()->get('body')->count()) {
          return AccessResult::forbidden();
        }
        break;

      case 'su_opp_application_deadline':
        if ($items->getEntity()->get('su_opp_event_date')->count()) {
          return AccessResult::forbidden();
        }
        break;
    }
  }

  // When edit an existing node that was imported via migrate module, mark the
  // fields that are mapped from migration as forbidden.
  if (
    $items &&
    $operation == 'edit' &&
    $route_match->getRouteName() == 'entity.node.edit_form'
  ) {

    $node = $route_match->getParameter('node');
    if (_cardinal_service_profile_field_mapped($node, $field_definition)) {
      return AccessResult::forbidden();
    }
  }
  return AccessResult::neutral();
}

/**
 * Check if the user is viewing the node related to the field items.
 *
 * @param string $operation
 *   User operation.
 * @param \Drupal\Core\Field\FieldItemListInterface|null $items
 *   Field items of the entity.
 *
 * @return bool
 *   True if the node for the field items is the current page.
 */
function _cardinal_service_profile_viewing_node_page($operation, FieldItemListInterface $items = NULL) {
  $route_match = \Drupal::routeMatch();
  if (
    $items &&
    $operation == 'view' &&
    $route_match->getRouteName() == 'entity.node.canonical' &&
    $items->getEntity()->getEntityTypeId() == 'node'
  ) {
    $node = $route_match->getParameter('node');
    return $node && $node->id() == $items->getEntity()->id();
  }
  return FALSE;
}

/**
 * Check if the field is mapped by a migration and the node was imported.
 *
 * @param \Drupal\node\NodeInterface $node
 *   Node entity being edited.
 * @param \Drupal\Core\Field\FieldDefinitionInterface $field
 *   Field to check for mapping.
 *
 * @return bool
 *   If the node is imported and the field is mapped.
 */
function _cardinal_service_profile_field_mapped(NodeInterface $node, FieldDefinitionInterface $field) {
  $field_name = $field->getName();
  $columns = $field->getFieldStorageDefinition()->getColumns();

  if ($migration_name = _cardinal_service_node_imported($node)) {
    $migration_config = \Drupal::config("migrate_plus.migration.$migration_name");
    $migration_group = \Drupal::config('migrate_plus.migration_group.' . $migration_config->get('migration_group'));

    $processing = FALSE;
    foreach (array_keys($columns) as $column) {
      $processing = !$processing ? $migration_config->get("process.$field_name/$column") : TRUE;
      $processing = $processing ?: $migration_group->get("shared_configuration.process.$field_name/$column");
    }

    // The field or a column of the field was mapped with data from migrate.
    // Mark it as forbidden.
    if (
      $processing ||
      $migration_config->get("process.$field_name") ||
      $migration_group->get("shared_configuration.process.$field_name")
    ) {
      return TRUE;
    }
  }

  return FALSE;
}

/**
 * Was this node imported via migrate module.
 *
 * @param \Drupal\node\NodeInterface $node
 *   Node entity.
 *
 * @return string|null
 *   True if it was imported from migration.
 */
function _cardinal_service_node_imported(NodeInterface $node) {
  $migration_names = \Drupal::configFactory()
    ->listAll('migrate_plus.migration.');

  foreach ($migration_names as $config_name) {
    $migration_name = str_replace('migrate_plus.migration.', '', $config_name);
    $db_name = 'migrate_map_' . $migration_name;
    $database = \Drupal::database();
    // Check for the table first.
    if (
      $database->schema()->tableExists($db_name) &&
      $database->schema()->fieldExists($db_name, 'destid1')
    ) {
      // Check for the entity id in the destination id column.
      $migrated = $database->select($db_name, 'm')
        ->fields('m')
        ->condition('destid1', $node->id())
        ->countQuery()
        ->execute()
        ->fetchField();

      if ($migrated > 0) {
        return $migration_name;
      }
    }
  }
}

/**
 * Implements hook_entity_bundle_field_info_alter().
 */
function cardinal_service_profile_entity_bundle_field_info_alter(&$fields, EntityTypeInterface $entity_type, $bundle) {
  if ($bundle === 'stanford_page') {
    $resource_fields = [
      'su_page_resource_type',
      'su_page_resource_audience',
      'su_page_resource_dimension',
    ];
    foreach ($resource_fields as $resource_field) {
      if (isset($fields[$resource_field])) {
        $fields[$resource_field]->addConstraint('ResourceFields', []);
      }
    }
  }
}