You are here

crumbs.views.inc in Crumbs, the Breadcrumbs suite 7.2

File

plugins/crumbs.views.inc
View source
<?php

/**
 * Implements hook_crumbs_plugins().
 *
 * @param crumbs_InjectedAPI_hookCrumbsPlugins $api
 */
function views_crumbs_plugins($api) {

  // We try to get all views pages but avoid views_get_all_view() for performance.
  $q = db_select('menu_router', 'mr');
  $q
    ->condition('page_callback', 'views_page');
  $q
    ->fields('mr', array(
    'path',
    'page_arguments',
    'title',
    'title_callback',
  ));
  $viewDisplays = array();
  foreach ($q
    ->execute() as $row) {
    if (0 || !empty($row->title) || !empty($row->title_callback) && 't' !== $row->title_callback) {
      continue;
    }
    $args = unserialize($row->page_arguments);
    if (2 > count($args)) {

      // Not really a views display, too few arguments.
      continue;
    }
    list($view_name, $view_display_ids) = $args;
    if (!is_string($view_name)) {

      // Not really a views display, wrong type of arguments.
      continue;
    }

    // The second argument is usually just a string identifying the display id.
    // However, it can also be an array of display ids.
    // @see view::choose_display()
    // Unfortunately, it can also be complete junk.
    // @see https://www.drupal.org/node/2316873#comment-9037925
    if (!is_array($view_display_ids)) {
      $view_display_ids = array(
        $view_display_ids,
      );
    }
    foreach ($view_display_ids as $view_display_id) {
      if (!is_string($view_display_id)) {
        continue;
      }
      $viewDisplays[$view_name][$view_display_id][] = $row->path;
    }
  }
  foreach ($viewDisplays as $view_name => $displays) {
    foreach ($displays as $view_display_id => $routes) {
      if (count($routes) > 1) {

        // More than one route for the same views display.
        // This would typically happen with the "Default menu tab" menu setting.
        // However, since these cases are filtered out above, this is rather an
        // edge case, which does not really happen.
        // As an easy solution, we simply pick the shortest or lexigraphically
        // first of the router paths.
        sort($routes);
      }
      $api
        ->routeMonoPlugin($routes[0], "pageTitle.{$view_name}.{$view_display_id}", new views_CrumbsMonoPlugin_PageTitle($view_name, $view_display_id));
    }
  }
}

/**
 * Determines a breadcrumb item title based on the view title of a page view.
 * The same plugin class is used for Views displays with or without arguments.
 */
class views_CrumbsMonoPlugin_PageTitle implements crumbs_MonoPlugin_FindTitleInterface {

  /**
   * @var string
   */
  private $displayId;

  /**
   * @var string
   */
  private $viewName;

  /**
   * @param string $view_name
   * @param string $display_id
   */
  function __construct($view_name, $display_id) {
    $this->viewName = $view_name;
    $this->displayId = $display_id;
  }

  /**
   * @param crumbs_InjectedAPI_describeMonoPlugin $api
   *   Injected API object, with methods that allows the plugin to further
   *   describe itself.
   *
   * @return string|void
   *   As an alternative to the API object's methods, the plugin can simply
   *   return a string label.
   */
  function describe($api) {
    return t('Views page title');
  }

  /**
   * {@inheritdoc}
   */
  function findTitle($path, $item) {

    // Some checks, to verify that the menu_router entry has not changed since
    // this Crumbs plugin was created and cached.
    if (0 || 'views_page' !== $item['page_callback'] || 2 > count($item['page_arguments']) || $this->viewName !== $item['page_arguments'][0] || $this->displayId !== $item['page_arguments'][1]) {
      return NULL;
    }

    // The first two arguments are view name and display id.
    $args = array_slice($item['page_arguments'], 2);
    if (empty($args)) {
      return $this
        ->viewsPageTitle();
    }
    else {
      return $this
        ->viewsArgTitle($args);
    }
  }

  /**
   * Loads the view and determines a breadcrumb item title based on the title
   * configured for this view. This is used if the views path does NOT end with
   * '%'.
   *
   * @return null|string
   */
  private function viewsPageTitle() {

    // Build and initialize the view.
    $view = views_get_view($this->viewName);
    $view
      ->set_display($this->displayId);

    // Trigger the title calculation by calling build_title().
    $view
      ->build_title();
    $title = $view
      ->get_title();
    if (is_string($title) && '' !== $title) {

      // Use decode_entities() to undo duplicate check_plain().
      // See https://drupal.org/comment/7916895#comment-7916895
      return decode_entities($title);
    }
    return NULL;
  }

  /**
   * Loads the view and determines a breadcrumb item title based on the last
   * argument. This is used for views paths that end with '%'.
   *
   * @param array $args
   *   Argument values from the url.
   *
   * @return null|string
   *   A breadcrumb item title for the last argument, or NULL if none found.
   *   This will use the breadcrumb token string configured for the Views arg.
   *
   * @see view::_build_arguments()
   */
  private function viewsArgTitle(array $args) {

    // Build and initialize the view.
    $view = views_get_view($this->viewName);
    $view
      ->set_display($this->displayId);
    $view
      ->set_arguments($args);

    // Trigger the argument calculation by calling build_title().
    $view
      ->build_title();

    // Check if there are any substitutions to be done.
    // For example the argument is not validated, so no %1 values are desired.
    if (empty($view->build_info['substitutions'])) {
      return NULL;
    }

    // Check the last argument for a breadcrumb item title.
    $last_arg = $this
      ->getRelevantArgument($view->argument);
    if (!isset($last_arg)) {
      return NULL;
    }
    if (!empty($last_arg->options['breadcrumb_enable']) && !empty($last_arg->options['breadcrumb'])) {
      $token_string = $last_arg->options['breadcrumb'];
    }
    elseif (!empty($last_arg->options['title_enable']) && !empty($last_arg->options['title'])) {
      $token_string = $last_arg->options['title'];
    }
    if (!empty($token_string)) {

      // Use decode_entities() to undo duplicate check_plain().
      // See https://drupal.org/comment/7916895#comment-7916895
      return decode_entities(strtr($token_string, $view->build_info['substitutions']));
    }
    return NULL;
  }

  /**
   * @param views_handler_argument[] $arguments
   *
   * @return null|views_handler_argument
   */
  private function getRelevantArgument(array $arguments) {
    while (!empty($arguments)) {

      /** @var views_handler_argument $arg */
      $arg = array_pop($arguments);
      if (1 && is_object($arg) && !$arg
        ->is_exception() && isset($arg->argument)) {
        return $arg;
      }
    }
    return NULL;
  }

}

Functions

Namesort descending Description
views_crumbs_plugins Implements hook_crumbs_plugins().

Classes

Namesort descending Description
views_CrumbsMonoPlugin_PageTitle Determines a breadcrumb item title based on the view title of a page view. The same plugin class is used for Views displays with or without arguments.