You are here

farm_ui_views.module in farmOS 2.x

The farmOS UI Views module.

File

modules/core/ui/views/farm_ui_views.module
View source
<?php

/**
 * @file
 * The farmOS UI Views module.
 */
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
use Drupal\views\ViewExecutable;

/**
 * Implements hook_help().
 */
function farm_ui_views_help($route_name, RouteMatchInterface $route_match) {
  $output = '';

  // Define common route names and URLs for primary entity types.
  $entity_routes = [
    'asset' => 'entity.asset.collection',
    'log' => 'entity.log.collection',
    'quantity' => 'view.farm_quantity.page',
    'people' => 'view.farm_people.page',
  ];
  $entity_urls = [
    'asset' => Url::fromRoute($entity_routes['asset'])
      ->toString(),
    'log' => Url::fromRoute($entity_routes['log'])
      ->toString(),
    'quantity' => Url::fromRoute($entity_routes['quantity'])
      ->toString(),
    'people' => Url::fromRoute($entity_routes['people'])
      ->toString(),
  ];

  // Assets View.
  if ($route_name == $entity_routes['asset']) {
    $output .= '<p>' . t('Assets represent things that are being tracked or managed. They store high-level information, but most historical data is stored in the <a href=":logs">logs</a> that reference them.', [
      ':logs' => $entity_urls['log'],
    ]) . '</p>';
    $output .= '<p>' . t('Assets that are no longer active can be archived. Archived assets will be hidden from most lists, but are preserved and searchable for posterity.') . '</p>';
  }

  // Logs View.
  if ($route_name == $entity_routes['log']) {
    $output .= '<p>' . t('Logs represent events that take place in relation to <a href=":assets">assets</a> and other records. They have a timestamp to represent when they take place, and can be marked as "Pending" or "Done" for planning purposes.', [
      ':assets' => $entity_urls['asset'],
    ]) . '</p>';
    $output .= '<p>' . t('Logs can be assigned to <a href=":people">people</a> for task management purposes.', [
      ':people' => $entity_urls['people'],
    ]) . '</p>';
  }

  // Quantities View.
  if ($route_name == $entity_routes['quantity']) {
    $output .= '<p>' . t('Quantities are granular units of quantitative data that represent a single data point within a <a href=":logs">log</a>.', [
      ':logs' => $entity_urls['log'],
    ]) . '</p>';
    $output .= '<p>' . t('All quantities can optionally include a measure, value, units, and label. Specific quantity types may collect additional information.') . '</p>';
  }

  // Plans View.
  if ($route_name == 'entity.plan.collection') {
    $output .= '<p>' . t('Plans provide features for planning, managing, and organizing <a href=":assets">assets</a>, <a href=":logs">logs</a>, and <a href=":people">people</a> around a particular goal.', [
      ':assets' => $entity_urls['asset'],
      ':logs' => $entity_urls['log'],
      ':people' => $entity_urls['people'],
    ]) . '</p>';
  }
  return $output;
}

/**
 * Implements hook_entity_type_build().
 */
function farm_ui_views_entity_type_build(array &$entity_types) {

  /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */

  // Override the "collection" link path for assets, logs, and plans to use
  // the Views provided by this module.
  $collection_paths = [
    'asset' => '/assets',
    'log' => '/logs',
    'plan' => '/plans',
  ];
  foreach ($collection_paths as $entity_type => $path) {
    if (!empty($entity_types[$entity_type])) {
      $entity_types[$entity_type]
        ->setLinkTemplate('collection', $path);
    }
  }
}

/**
 * Implements hook_local_tasks_alter().
 */
function farm_ui_views_local_tasks_alter(&$local_tasks) {

  // Remove the local task plugin definition for farm entity collection links.
  $entity_types = [
    'asset',
    'log',
    'plan',
  ];
  foreach ($entity_types as $type) {
    if (!empty($local_tasks["entity.{$type}.collection"])) {
      unset($local_tasks["entity.{$type}.collection"]);
    }
  }
}

/**
 * Implements hook_form_BASE_FORM_ID_alter().
 */
function farm_ui_views_form_views_exposed_form_alter(&$form, FormStateInterface $form_state, $form_id) {

  // Load form state storage and bail if the View is not stored.
  $storage = $form_state
    ->getStorage();
  if (empty($storage['view'])) {
    return;
  }

  // We only want to alter the Views we provide.
  if (!in_array($storage['view']
    ->id(), [
    'farm_asset',
    'farm_log',
    'farm_plan',
  ])) {
    return;
  }

  // If there is no exposed filter for flags, bail.
  if (empty($form['flag_value'])) {
    return;
  }

  // Get the entity type and (maybe) bundle.
  $entity_type = $storage['view']
    ->getBaseEntityType()
    ->id();
  $bundle = farm_ui_views_get_bundle_argument($storage['view'], $storage['display']['id'], $storage['view']->args);

  // Load flag entities and filter out ones that don't apply.

  /** @var \Drupal\farm_flag\Entity\FarmFlagInterface[] $flags */
  $flags = \Drupal::entityTypeManager()
    ->getStorage('flag')
    ->loadMultiple();
  $allowed_flag_ids = [];
  foreach ($flags as $flag) {
    if (farm_flag_applies($flag, $entity_type, $bundle)) {
      $allowed_flag_ids[] = $flag
        ->id();
    }
  }

  // Alter exposed filters to remove flags that are not applicable.
  $allowed_options = [];
  foreach ($form['flag_value']['#options'] as $key => $value) {
    if (in_array($key, $allowed_flag_ids)) {
      $allowed_options[$key] = $value;
    }
  }
  $form['flag_value']['#options'] = $allowed_options;
}

/**
 * Implements hook_farm_dashboard_groups().
 */
function farm_ui_views_farm_dashboard_groups() {
  $groups = [];

  // If the plan module is enabled, add a plans group.
  if (\Drupal::service('module_handler')
    ->moduleExists('plan')) {
    $groups['second']['plans'] = [
      '#weight' => 10,
    ];
  }

  // Add a logs group.
  $groups['first']['logs'] = [
    '#weight' => 10,
  ];
  return $groups;
}

/**
 * Implements hook_farm_dashboard_panes().
 */
function farm_ui_views_farm_dashboard_panes() {
  $panes = [];

  // If the plan module is enabled, add active plans pane.
  if (\Drupal::service('module_handler')
    ->moduleExists('plan')) {
    $panes['active_plans'] = [
      'view' => 'farm_plan',
      'view_display_id' => 'block_active',
      'group' => 'plans',
      'region' => 'second',
      'weight' => 0,
    ];
  }

  // Add upcoming and late logs panes.
  $panes['upcoming_tasks'] = [
    'view' => 'farm_log',
    'view_display_id' => 'block_upcoming',
    'group' => 'logs',
    'region' => 'first',
    'weight' => 10,
  ];
  $panes['late_tasks'] = [
    'view' => 'farm_log',
    'view_display_id' => 'block_late',
    'group' => 'logs',
    'region' => 'first',
    'weight' => 11,
  ];
  return $panes;
}

/**
 * Implements hook_entity_base_field_info_alter().
 */
function farm_ui_views_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) {

  // Use Entity Browser widget for certain asset reference fields.
  $alter_fields = [
    'log' => [
      'asset',
    ],
    'quantity' => [
      'inventory_asset',
    ],
  ];
  foreach ($alter_fields as $entity_type_id => $field_names) {
    if ($entity_type
      ->id() != $entity_type_id) {
      continue;
    }
    foreach ($field_names as $field_name) {
      if (!empty($fields[$field_name])) {

        /** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */
        $form_display_options = $fields[$field_name]
          ->getDisplayOptions('form');
        $form_display_options['type'] = 'entity_browser_entity_reference';
        $form_display_options['settings'] = [
          'entity_browser' => 'farm_asset',
          'field_widget_display' => 'label',
          'field_widget_remove' => TRUE,
          'open' => TRUE,
          'selection_mode' => 'selection_append',
          'field_widget_edit' => FALSE,
          'field_widget_replace' => FALSE,
          'field_widget_display_settings' => [],
        ];
        $fields[$field_name]
          ->setDisplayOptions('form', $form_display_options);
      }
    }
  }
}

/**
 * Helper function for sorting a field handler.
 *
 * Based off the \Drupal\views_ui\Form\Ajax\Rearrange.php method of ordering
 * handlers in views.
 *
 * @param \Drupal\views\ViewExecutable $view
 *   The View to add handlers to.
 * @param string $display_id
 *   The ID of the View display to add handlers to.
 * @param string $field_id
 *   The ID of the field to sort.
 * @param string $base_field_id
 *   The ID of an existing field in the View. The field defined by $field_id
 *   will be added before/after this field in the View.
 * @param bool $before
 *   If TRUE, the field will be added before the field defined by $base_field_id
 *   instead of after.
 */
function farm_ui_views_sort_field(ViewExecutable $view, string $display_id, string $field_id, string $base_field_id, bool $before = FALSE) {

  // Get the existing field handlers.
  $type = 'field';
  $types = ViewExecutable::getHandlerTypes();
  $display = $view->displayHandlers
    ->get($display_id);
  $field_handlers = $display
    ->getOption($types[$type]['plural']);

  // Define the new field handler and insert at desired position.
  $new_field_handler = [
    $field_id => $field_handlers[$field_id],
  ];
  $keys = array_keys($field_handlers);
  $index = array_search($base_field_id, $keys, TRUE);
  $pos = empty($index) ? count($field_handlers) : $index;
  if (!$before) {
    $pos++;
  }
  $new_field_handlers = array_merge(array_slice($field_handlers, 0, $pos, TRUE), $new_field_handler, array_slice($field_handlers, $pos, NULL, TRUE));

  // Set the display to use the sorted field handlers.
  $display
    ->setOption($types[$type]['plural'], $new_field_handlers);
}

/**
 * Helper function for getting the bundle from a "By Type" display's arguments.
 *
 * @param \Drupal\views\ViewExecutable $view
 *   The View object.
 * @param string $display_id
 *   The display ID.
 * @param array $args
 *   Arguments for the View.
 *
 * @return string
 *   Returns the bundle, or empty string if no bundle argument is found.
 */
function farm_ui_views_get_bundle_argument(ViewExecutable $view, string $display_id, array $args) {
  $bundle = '';
  if ($display_id == 'page_type' && !empty($args[0])) {
    $bundle = $args[0];
  }
  elseif ($view
    ->id() == 'farm_log' && $display_id == 'page_asset' && !empty($args[1]) && $args[1] != 'all') {
    $bundle = $args[1];
  }
  return $bundle;
}