You are here

views_ui.module in Drupal 10

Provide structure for the administrative interface to Views.

File

core/modules/views_ui/views_ui.module
View source
<?php

/**
 * @file
 * Provide structure for the administrative interface to Views.
 */
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
use Drupal\views\ViewExecutable;
use Drupal\views\Analyzer;

/**
 * Implements hook_help().
 */
function views_ui_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {
    case 'help.page.views_ui':
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('The Views UI module provides an interface for managing views for the <a href=":views">Views module</a>. For more information, see the <a href=":handbook">online documentation for the Views UI module</a>.', [
        ':views' => Url::fromRoute('help.page', [
          'name' => 'views',
        ])
          ->toString(),
        ':handbook' => 'https://www.drupal.org/documentation/modules/views_ui',
      ]) . '</p>';
      $output .= '<h3>' . t('Uses') . '</h3>';
      $output .= '<dl>';
      $output .= '<dt>' . t('Creating and managing views') . '</dt>';
      $output .= '<dd>' . t('Views can be created from the <a href=":list">Views list page</a> by using the "Add view" action. Existing views can be managed from the <a href=":list">Views list page</a> by locating the view in the "Enabled" or "Disabled" list and selecting the desired operation action, for example "Edit".', [
        ':list' => Url::fromRoute('entity.view.collection', [
          'name' => 'views_ui',
        ])
          ->toString(),
      ]) . '</dd>';
      $output .= '<dt>' . t('Enabling and disabling views') . '<dt>';
      $output .= '<dd>' . t('Views can be enabled or disabled from the <a href=":list">Views list page</a>. To enable a view, find the view within the "Disabled" list and select the "Enable" operation. To disable a view find the view within the "Enabled" list and select the "Disable" operation.', [
        ':list' => Url::fromRoute('entity.view.collection', [
          'name' => 'views_ui',
        ])
          ->toString(),
      ]) . '</dd>';
      $output .= '<dt>' . t('Exporting and importing views') . '</dt>';
      $output .= '<dd>' . t('Views can be exported and imported as configuration files by using the <a href=":config">Configuration Manager module</a>.', [
        ':config' => \Drupal::moduleHandler()
          ->moduleExists('config') ? Url::fromRoute('help.page', [
          'name' => 'config',
        ])
          ->toString() : '#',
      ]) . '</dd>';
      $output .= '</dl>';
      return $output;
  }
}

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

  /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
  $entity_types['view']
    ->setFormClass('edit', 'Drupal\\views_ui\\ViewEditForm')
    ->setFormClass('add', 'Drupal\\views_ui\\ViewAddForm')
    ->setFormClass('preview', 'Drupal\\views_ui\\ViewPreviewForm')
    ->setFormClass('duplicate', 'Drupal\\views_ui\\ViewDuplicateForm')
    ->setFormClass('delete', 'Drupal\\Core\\Entity\\EntityDeleteForm')
    ->setFormClass('break_lock', 'Drupal\\views_ui\\Form\\BreakLockForm')
    ->setListBuilderClass('Drupal\\views_ui\\ViewListBuilder')
    ->setLinkTemplate('edit-form', '/admin/structure/views/view/{view}')
    ->setLinkTemplate('edit-display-form', '/admin/structure/views/view/{view}/edit/{display_id}')
    ->setLinkTemplate('preview-form', '/admin/structure/views/view/{view}/preview/{display_id}')
    ->setLinkTemplate('duplicate-form', '/admin/structure/views/view/{view}/duplicate')
    ->setLinkTemplate('delete-form', '/admin/structure/views/view/{view}/delete')
    ->setLinkTemplate('enable', '/admin/structure/views/view/{view}/enable')
    ->setLinkTemplate('disable', '/admin/structure/views/view/{view}/disable')
    ->setLinkTemplate('break-lock-form', '/admin/structure/views/view/{view}/break-lock')
    ->setLinkTemplate('collection', '/admin/structure/views');
}

/**
 * Implements hook_theme().
 */
function views_ui_theme() {
  return [
    // edit a view
    'views_ui_display_tab_setting' => [
      'variables' => [
        'description' => '',
        'link' => '',
        'settings_links' => [],
        'overridden' => FALSE,
        'defaulted' => FALSE,
        'description_separator' => TRUE,
        'class' => [],
      ],
      'file' => 'views_ui.theme.inc',
    ],
    'views_ui_display_tab_bucket' => [
      'render element' => 'element',
      'file' => 'views_ui.theme.inc',
    ],
    'views_ui_rearrange_filter_form' => [
      'render element' => 'form',
      'file' => 'views_ui.theme.inc',
    ],
    'views_ui_expose_filter_form' => [
      'render element' => 'form',
      'file' => 'views_ui.theme.inc',
    ],
    // Legacy theme hook for displaying views info.
    'views_ui_view_info' => [
      'variables' => [
        'view' => NULL,
        'displays' => NULL,
      ],
      'file' => 'views_ui.theme.inc',
    ],
    // List views.
    'views_ui_views_listing_table' => [
      'variables' => [
        'headers' => NULL,
        'rows' => NULL,
        'attributes' => [],
      ],
      'file' => 'views_ui.theme.inc',
    ],
    'views_ui_view_displays_list' => [
      'variables' => [
        'displays' => [],
      ],
    ],
    // Group of filters.
    'views_ui_build_group_filter_form' => [
      'render element' => 'form',
      'file' => 'views_ui.theme.inc',
    ],
    // On behalf of a plugin
    'views_ui_style_plugin_table' => [
      'render element' => 'form',
      'file' => 'views_ui.theme.inc',
    ],
    // When previewing a view.
    'views_ui_view_preview_section' => [
      'variables' => [
        'view' => NULL,
        'section' => NULL,
        'content' => NULL,
        'links' => '',
      ],
      'file' => 'views_ui.theme.inc',
    ],
    // Generic container wrapper, to use instead of theme_container when an id
    // is not desired.
    'views_ui_container' => [
      'variables' => [
        'children' => NULL,
        'attributes' => [],
      ],
      'file' => 'views_ui.theme.inc',
    ],
  ];
}

/**
 * Implements hook_preprocess_HOOK() for views templates.
 */
function views_ui_preprocess_views_view(&$variables) {
  $view = $variables['view'];

  // Render title for the admin preview.
  if (!empty($view->live_preview)) {
    $variables['title'] = [
      '#markup' => $view
        ->getTitle(),
    ];
  }
  if (!empty($view->live_preview) && \Drupal::moduleHandler()
    ->moduleExists('contextual')) {
    $view
      ->setShowAdminLinks(FALSE);
    foreach ([
      'title',
      'header',
      'exposed',
      'rows',
      'pager',
      'more',
      'footer',
      'empty',
      'attachment_after',
      'attachment_before',
    ] as $section) {
      if (!empty($variables[$section])) {
        $variables[$section] = [
          '#theme' => 'views_ui_view_preview_section',
          '#view' => $view,
          '#section' => $section,
          '#content' => $variables[$section],
          '#theme_wrappers' => [
            'views_ui_container',
          ],
          '#attributes' => [
            'class' => [
              'contextual-region',
            ],
          ],
        ];
      }
    }
  }
}

/**
 * Implements hook_theme_suggestions_HOOK().
 */
function views_ui_theme_suggestions_views_ui_view_preview_section(array $variables) {
  return [
    'views_ui_view_preview_section__' . $variables['section'],
  ];
}

/**
 * Returns contextual links for each handler of a certain section.
 *
 * @TODO
 *   Bring in relationships
 *   Refactor this function to use much stuff of views_ui_edit_form_get_bucket.
 *
 * @param $title
 *   Add a bolded title of this section.
 */
function views_ui_view_preview_section_handler_links(ViewExecutable $view, $type, $title = FALSE) {
  $display = $view->display_handler->display;
  $handlers = $view->display_handler
    ->getHandlers($type);
  $links = [];
  $types = ViewExecutable::getHandlerTypes();
  if ($title) {
    $links[$type . '-title'] = [
      'title' => $types[$type]['title'],
    ];
  }
  foreach ($handlers as $id => $handler) {
    $field_name = $handler
      ->adminLabel(TRUE);
    $links[$type . '-edit-' . $id] = [
      'title' => t('Edit @section', [
        '@section' => $field_name,
      ]),
      'url' => Url::fromRoute('views_ui.form_handler', [
        'js' => 'nojs',
        'view' => $view->storage
          ->id(),
        'display_id' => $display['id'],
        'type' => $type,
        'id' => $id,
      ]),
      'attributes' => [
        'class' => [
          'views-ajax-link',
        ],
      ],
    ];
  }
  $links[$type . '-add'] = [
    'title' => t('Add new'),
    'url' => Url::fromRoute('views_ui.form_add_handler', [
      'js' => 'nojs',
      'view' => $view->storage
        ->id(),
      'display_id' => $display['id'],
      'type' => $type,
    ]),
    'attributes' => [
      'class' => [
        'views-ajax-link',
      ],
    ],
  ];
  return $links;
}

/**
 * Returns a link to editing a certain display setting.
 */
function views_ui_view_preview_section_display_category_links(ViewExecutable $view, $type, $title) {
  $display = $view->display_handler->display;
  $links = [
    $type . '-edit' => [
      'title' => t('Edit @section', [
        '@section' => $title,
      ]),
      'url' => Url::fromRoute('views_ui.form_display', [
        'js' => 'nojs',
        'view' => $view->storage
          ->id(),
        'display_id' => $display['id'],
        'type' => $type,
      ]),
      'attributes' => [
        'class' => [
          'views-ajax-link',
        ],
      ],
    ],
  ];
  return $links;
}

/**
 * Returns all contextual links for the main content part of the view.
 */
function views_ui_view_preview_section_rows_links(ViewExecutable $view) {
  $links = [];
  $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'filter', TRUE));
  $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'field', TRUE));
  $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'sort', TRUE));
  $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'argument', TRUE));
  $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'relationship', TRUE));
  return $links;
}

/**
 * Implements hook_views_plugins_display_alter().
 */
function views_ui_views_plugins_display_alter(&$plugins) {

  // Attach contextual links to each display plugin. The links will point to
  // paths underneath "admin/structure/views/view/{$view->id()}" (i.e., paths
  // for editing and performing other contextual actions on the view).
  foreach ($plugins as &$display) {
    $display['contextual links']['entity.view.edit_form'] = [
      'route_name' => 'entity.view.edit_form',
      'route_parameters_names' => [
        'view' => 'id',
      ],
    ];
  }
}

/**
 * Implements hook_contextual_links_view_alter().
 */
function views_ui_contextual_links_view_alter(&$element, $items) {

  // Remove contextual links from being rendered, when so desired, such as
  // within a View preview.
  if (views_ui_contextual_links_suppress()) {
    $element['#links'] = [];
  }
  elseif (!empty($element['#links']['entityviewedit-form'])) {
    $display_id = $items['entity.view.edit_form']['metadata']['display_id'];
    $route_parameters = $element['#links']['entityviewedit-form']['url']
      ->getRouteParameters() + [
      'display_id' => $display_id,
    ];
    $element['#links']['entityviewedit-form']['url'] = Url::fromRoute('entity.view.edit_display_form', $route_parameters);
  }
}

/**
 * Sets a static variable for controlling whether contextual links are rendered.
 *
 * @see views_ui_contextual_links_view_alter()
 */
function views_ui_contextual_links_suppress($set = NULL) {
  $suppress =& drupal_static(__FUNCTION__);
  if (isset($set)) {
    $suppress = $set;
  }
  return $suppress;
}

/**
 * Increments the views_ui_contextual_links_suppress() static variable.
 *
 * When this function is added to the #pre_render of an element, and
 * 'views_ui_contextual_links_suppress_pop' is added to the #post_render of the
 * same element, then all contextual links within the element and its
 * descendants are suppressed from being rendered. This is used, for example,
 * during a View preview, when it is not desired for nodes in the Views result
 * to have contextual links.
 *
 * @see views_ui_contextual_links_suppress_pop()
 */
function views_ui_contextual_links_suppress_push() {
  views_ui_contextual_links_suppress((int) views_ui_contextual_links_suppress() + 1);
}

/**
 * Decrements the views_ui_contextual_links_suppress() static variable.
 *
 * @see views_ui_contextual_links_suppress_push()
 */
function views_ui_contextual_links_suppress_pop() {
  views_ui_contextual_links_suppress((int) views_ui_contextual_links_suppress() - 1);
}

/**
 * Implements hook_views_analyze().
 *
 * This is the basic views analysis that checks for very minimal problems.
 * There are other analysis tools in core specific sections, such as
 * node.views.inc as well.
 */
function views_ui_views_analyze(ViewExecutable $view) {
  $ret = [];

  // Check for something other than the default display:
  if (count($view->displayHandlers) < 2) {
    $ret[] = Analyzer::formatMessage(t('This view has only a default display and therefore will not be placed anywhere on your site; perhaps you want to add a page or a block display.'), 'warning');
  }

  // If a display has a path, check that it does not match an existing path
  // alias. This results in the path alias not working.
  foreach ($view->displayHandlers as $display) {
    if (empty($display)) {
      continue;
    }
    if ($display
      ->hasPath() && ($path = $display
      ->getOption('path'))) {
      $normal_path = \Drupal::service('path_alias.manager')
        ->getPathByAlias($path);
      if ($path != $normal_path) {
        $ret[] = Analyzer::formatMessage(t('You have configured display %display with a path which is an path alias as well. This might lead to unwanted effects so better use an internal path.', [
          '%display' => $display->display['display_title'],
        ]), 'warning');
      }
    }
  }
  return $ret;
}

/**
 * Truncate strings to a set length and provide a '...' if they truncated.
 *
 * This is often used in the UI to ensure long strings fit.
 */
function views_ui_truncate($string, $length) {
  if (mb_strlen($string) > $length) {
    $string = mb_substr($string, 0, $length);
    $string .= '...';
  }
  return $string;
}

Functions

Namesort descending Description
views_ui_contextual_links_suppress Sets a static variable for controlling whether contextual links are rendered.
views_ui_contextual_links_suppress_pop Decrements the views_ui_contextual_links_suppress() static variable.
views_ui_contextual_links_suppress_push Increments the views_ui_contextual_links_suppress() static variable.
views_ui_contextual_links_view_alter Implements hook_contextual_links_view_alter().
views_ui_entity_type_build Implements hook_entity_type_build().
views_ui_help Implements hook_help().
views_ui_preprocess_views_view Implements hook_preprocess_HOOK() for views templates.
views_ui_theme Implements hook_theme().
views_ui_theme_suggestions_views_ui_view_preview_section Implements hook_theme_suggestions_HOOK().
views_ui_truncate Truncate strings to a set length and provide a '...' if they truncated.
views_ui_views_analyze Implements hook_views_analyze().
views_ui_views_plugins_display_alter Implements hook_views_plugins_display_alter().
views_ui_view_preview_section_display_category_links Returns a link to editing a certain display setting.
views_ui_view_preview_section_handler_links Returns contextual links for each handler of a certain section.
views_ui_view_preview_section_rows_links Returns all contextual links for the main content part of the view.