You are here

bean_usage.module in Bean (for Drupal 7) 7

Bean Admin Functions and Display

File

bean_usage/bean_usage.module
View source
<?php

/* @file
 * Show where Beans are used.
 * Currently limited to beans displayed with blockreference.
 *
 */

/**
 * Implements hook_menu()
 *
 * @return array
 */
function bean_usage_menu() {
  $items = array();

  // Todo: beans can be placed via context and block admin - we should account for those as well.
  // usage tab on bean view
  $items['block/%bean_delta/usage'] = array(
    'title' => 'Usage',
    'description' => 'Displays a list of entities where this bean is used.',
    'type' => MENU_LOCAL_TASK,
    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
    'page callback' => 'bean_usage_output',
    'page arguments' => array(
      1,
    ),
    'access arguments' => array(
      'view bean usage',
    ),
  );

  // bean usage report
  $items['admin/reports/bean/usage'] = array(
    'title' => t('Bean usage'),
    'description' => 'Displays a list of Beans (blockreferences) and where they are used.',
    'page callback' => 'bean_usage_output',
    'page arguments' => array(
      4,
    ),
    'access arguments' => array(
      'view bean usage',
    ),
  );
  $items['admin/reports/bean/usage/list'] = array(
    'title' => t('Usage'),
    'description' => 'Displays a list of Beans (blockreferences) and where they are used.',
    'weight' => 0,
    'page callback' => 'bean_usage_output',
    'page arguments' => array(
      5,
    ),
    'access arguments' => array(
      'view bean usage',
    ),
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );
  $items['admin/reports/bean/usage/settings'] = array(
    'title' => t('Settings'),
    'description' => t('Displays a list of Beans (blockreferences) and where they are used.'),
    'weight' => 1,
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'bean_usage_settings',
    ),
    'access arguments' => array(
      'administer bean usage',
    ),
    'file' => 'includes/bean_usage.forms.inc',
    'type' => MENU_LOCAL_TASK | MENU_NORMAL_ITEM,
  );
  return $items;
}

/**
 * Implements hook_permission()
 *
 * @return array
 */
function bean_usage_permission() {
  $perms = array(
    'view bean usage' => array(
      'title' => t('View bean usage'),
      'description' => t('View a list of Beans (blockreferences) and where they are used.'),
    ),
    'administer bean usage' => array(
      'title' => t('Administer bean usage'),
      'description' => t('Administer settings for the bean usage page.'),
    ),
  );
  return $perms;
}

/**
 * @file
 * Bean Admin Functions and Display
 */

/**
 * Displays a table of Beans and their usage
 *
 * @return string - the HTML for the table
 */
function bean_usage_output($bean = NULL) {
  module_load_include('inc', 'bean_usage', 'includes/bean_usage.forms');
  $output = '';
  $bean_delta = NULL;
  $delta_specific = $delta_found = FALSE;
  $bean_usage_form = drupal_get_form('bean_usage_filters');
  if (!empty($bean) && is_object($bean)) {
    $delta_specific = TRUE;
  }
  else {
    if (is_numeric($bean)) {
      $delta_specific = TRUE;
      $bean = bean_load($bean);
    }
  }
  if (is_object($bean)) {
    drupal_set_title($bean->label . ' Usage');
    $bean_delta = $bean->delta;
  }

  // Get all fields that are of type blockreference and not deleted
  $fields = bean_usage_blockreference_fields();

  // If we have something to work with
  if (!empty($fields)) {
    $filters = drupal_get_query_parameters();
    if ($delta_specific) {
      $delta_found = FALSE;
    }
    $entity_types = bean_usage_blockrefence_entity_types();
    $bundles = bean_usage_blockreference_bundles();
    $query = '';
    foreach ($fields as $i => $field) {
      if (!$delta_found) {
        $field_name = $field->name;
        $data_table = 'field_data_' . $field_name;
        if ($i == 0) {
          $query = _bean_usage_field_data($data_table, $i, $field_name, $entity_types, $bundles, $filters, $delta_specific, $bean);
        }
        else {
          $query
            ->union(_bean_usage_field_data($data_table, $i, $field_name, $entity_types, $bundles, $filters, $delta_specific, $bean));
        }
      }
    }

    // Get the data
    $data = $query
      ->execute()
      ->fetchAll(0);
    if (!empty($data)) {

      // Sort the data - default sort is by label
      usort($data, 'bean_usage_sort_by_label');
      if (!empty($_GET['order'])) {
        $sort_by = empty($_GET['order']) ? '' : str_replace('bean ', '', strtolower($_GET['order']));
        switch ($sort_by) {
          case 'label':
            usort($data, 'bean_usage_sort_by_label');
            break;
          case 'title':
            usort($data, 'bean_usage_sort_by_title');
            break;
          case 'type':
            usort($data, 'bean_usage_sort_by_type');
            break;
        }
      }
      if (!empty($_GET['sort']) && $_GET['sort'] == 'desc') {
        $data = array_reverse($data);
      }
      $content = array();
      foreach ($data as $bean_data) {

        // We want to link to display the entity type title/name
        $entity_title = '';
        switch ($bean_data->entity_type) {

          // If its a node, get the node title
          case 'node':
            $entity_title = _bean_usage_entity_display('node', $bean_data->entity_id, 'nid', 'title');
            break;

          // If its a user, get the user name
          case 'user':
            $entity_title = _bean_usage_entity_display('user', $bean_data->entity_id, 'uid', 'name');
            break;
        }
        $content[$bean_data->label][$bean_data->entity_type][$bean_data->entity_id]['bean_title'] = $bean_data->title;
        $content[$bean_data->label][$bean_data->entity_type][$bean_data->entity_id]['bean_type'] = $bean_data->type;
        $content[$bean_data->label][$bean_data->entity_type][$bean_data->entity_id]['entity_id'] = $bean_data->entity_id;
        $content[$bean_data->label][$bean_data->entity_type][$bean_data->entity_id]['entity_title'] = $entity_title;
        if ($delta_specific) {
          $delta_found = TRUE;
        }
      }
    }

    // If we have any usage data create and display the table of data
    if (!empty($content)) {
      $rows = count($content);
      $results_per_page = variable_get('bean_usage_results_per_page', 30);

      // set up pager variables
      pager_default_initialize($rows, $results_per_page, $element = 0);

      // Set up output table
      $bean_table_data = array(
        'attributes' => array(
          // set table attributes
          'width' => '100%',
        ),
        'header' => _bean_usage_table_headers($bean_delta),
        'rows' => array(),
      );
      if ($filters) {
        $bean_table_data['caption'] = t('Filters: ') . $filters;
      }

      // Get the result subset for the current page
      $page = empty($_GET['page']) ? 0 : $_GET['page'];
      $range_start = $page * $results_per_page;
      $usage = array_slice($content, $range_start, $results_per_page);

      // If the user is on a higher page and then filters, the page
      if (!empty($filters) && $page != 0 && count($usage) == 0) {
        while (count($usage) == 0) {
          $page--;
          $range_start = $page * $results_per_page;
          $usage = array_slice($content, $range_start, $results_per_page);
        }
      }
      foreach ($usage as $bean_label => $entity_type) {
        foreach ($entity_type as $type => $delta) {
          $rowspan = count($delta);
          $bean_label_cell = '';
          if (empty($bean_delta)) {
            $bean_label_cell = array(
              'data' => $bean_label,
              'rowspan' => $rowspan,
              'width' => '30%',
            );
          }

          // we create the row with the bean name first and set the rowspan to however many deltas there are
          foreach ($delta as $entity) {
            $bean_title_cell = array(
              'data' => empty($entity['bean_title']) ? '<em>' . t('No title set') . '</em>' : $entity['bean_title'],
              'rowspan' => $rowspan,
              'width' => '30%',
            );
            $bean_type_cell = array(
              'data' => $entity['bean_type'],
              'rowspan' => $rowspan,
              'width' => '10%',
            );

            // We want to prefix the entity title with the entity id
            // We also want the entity title to link back the to the entity page
            $link_prefix = '';
            $text_prefix = '';
            switch ($type) {
              case 'node':
                $text_prefix = '[nid:' . $entity['entity_id'] . '] ';
                $link_prefix = 'node/';
                break;
              case 'user':
                $text_prefix = '[uid:' . $entity['entity_id'] . '] ';
                $link_prefix = 'user/';
                break;
            }

            // switch ($entity_type)
            // add the usage data to the table
            // We only need to add the Bean label once per delta, Since we set it above we check for its emptiness
            if (!empty($bean_label_cell)) {
              $bean_table_data['rows'][] = array(
                0 => $bean_label_cell,
                1 => $bean_title_cell,
                2 => $bean_type_cell,
                3 => array(
                  'data' => $text_prefix . l($entity['entity_title'], $link_prefix . $entity['entity_id']),
                  'width' => '30%',
                  'no_striping' => TRUE,
                ),
              );
            }
            else {
              $bean_table_data['rows'][] = array(
                $text_prefix . l(t($entity['entity_title']), $link_prefix . $entity['entity_id'], array(
                  'attributes' => array(
                    'title' => $entity['entity_title'],
                    'target' => '_blank',
                  ),
                )),
              );
            }

            // else
            // empty out the $bean_row so that it doesn't display more than one if there are multiple deltas for the block
            $bean_label_cell = '';
          }

          // foreach ($delta)
        }

        //foreach ($entity_type)
      }

      // foreach ($usage)
      // Set the output using theme_table with the header and rows created above
      if (!$delta_specific) {
        $output .= drupal_render($bean_usage_form);
      }
      $output .= theme('table', $bean_table_data);
      $output .= theme('pager');
    }
    else {
      if ($delta_specific) {
        $output = '<p>' . t('This bean is not used anywhere on the site.') . '</p>';
      }
      else {
        $output .= $bean_usage_form;
        $output .= 'There is no bean usage to report for ' . $filters;
      }
    }

    // else
  }

  // if (!empty($fields))
  // return the output for page rendering
  return $output;
}

/**
 * Get all fields that are of type blockreference and not deleted
 *
 * @return mixed
 */
function bean_usage_blockreference_fields() {
  $fields =& drupal_static(__FUNCTION__);
  if (!isset($fields)) {
    $query = db_select('field_config', 'fc');
    $query
      ->addField('fc', 'field_name', 'name');
    $query
      ->leftJoin('field_config_instance', 'fci', 'fc.field_name = fci.field_name');
    $fields = $query
      ->condition('fc.type', 'blockreference')
      ->condition('fc.deleted', 0)
      ->orderBy('fc.field_name', 'asc')
      ->execute()
      ->fetchAll(0);
  }
  return $fields;
}

/**
 * Get all of the entity types used with beans via blockreference
 *
 * @return array
 */
function bean_usage_blockrefence_entity_types() {
  $entity_types = array();
  $et_query = db_select('field_config_instance', 'fci')
    ->distinct();
  $et_query
    ->addField('fci', 'entity_type', 'type');
  $et_query
    ->join('field_config', 'fc', 'fc.field_name = fci.field_name');
  $et_res = $et_query
    ->condition('fc.type', 'blockreference')
    ->execute()
    ->fetchAll(0);
  foreach ($et_res as $entity) {
    $entity_types[] = $entity->type;
  }
  return $entity_types;
}

/**
 * Get all of the bundles used with beans via blockreference
 *
 * @return array
 */
function bean_usage_blockreference_bundles() {
  $bundles = array();
  $b_query = db_select('field_config_instance', 'fci')
    ->distinct();
  $b_query
    ->join('field_config', 'fc', 'fc.field_name = fci.field_name');
  $b_res = $b_query
    ->fields('fci', array(
    'bundle',
  ))
    ->condition('fc.type', 'blockreference')
    ->execute()
    ->fetchAll(0);
  foreach ($b_res as $bundle) {
    $bundles[] = $bundle->bundle;
  }
  return $bundles;
}

/**
 * Helper function to display an entity on the report
 *
 * @param $table
 * @param $value
 * @param $key
 * @param $column
 * @return mixed
 */
function _bean_usage_entity_display($table, $value, $key, $column) {
  $query = db_select($table, 't')
    ->fields('t', array(
    $column,
  ))
    ->condition($key, $value)
    ->execute()
    ->fetchAssoc();
  return $query[$column];
}

/**
 * Get the data from the field_data tables for bean usage based on bean.bid and bean.delta
 *
 * @param string $data_table
 * @param int $i
 * @param string $field_name
 * @param array $entity_types
 * @param array $bundles
 * @param string $filter
 * @param boolean $delta_specific
 * @param object bean
 *
 * @return SelectQuery
 */
function _bean_usage_field_data($data_table, $i, $field_name, $entity_types, $bundles, $filters = NULL, $delta_specific = FALSE, $bean = NULL) {
  $query = db_select($data_table, 'fd' . $i);
  $query
    ->leftJoin('block', 'bl', 'fd' . $i . '.' . $field_name . '_bid = bl.bid');
  $query
    ->join('bean', 'b', 'b.delta = bl.delta');
  $query
    ->fields('b', array(
    'bid',
    'label',
    'title',
    'type',
  ));
  $query
    ->fields('fd' . $i, array(
    'entity_id',
    'delta',
    'entity_type',
  ));
  $query
    ->addField('fd' . $i, $field_name . '_bid', 'bid');
  $query_and = db_and();
  $query_and
    ->condition('bl.module', 'bean');
  $query_and
    ->condition('bl.theme', variable_get('theme_default', NULL));
  $query_and
    ->condition('fd' . $i . '.entity_type', $entity_types, 'IN');
  $query_and
    ->condition('fd' . $i . '.bundle', $bundles, 'IN');
  if (!empty($filters['type'])) {
    $query_and
      ->condition('b.type', array(
      $filters['type'],
    ), 'IN');
  }
  if (!empty($filters['title'])) {
    $query_and
      ->condition('b.title', '%' . $filters['title'] . '%', 'LIKE');
  }
  if (!empty($filters['label'])) {
    $query_and
      ->condition('b.label', '%' . $filters['label'] . '%', 'LIKE');
  }
  if ($delta_specific && !empty($bean)) {
    $query_and
      ->condition('b.bid', intval($bean->bid));
  }
  $query
    ->condition($query_and);
  return $query;
}

/**
 * Set the table headers for the table output based on the page that calls for the data.
 *
 * @param null $bean_delta
 *
 * @return array
 */
function _bean_usage_table_headers($bean_delta = NULL) {
  if (empty($bean_delta)) {
    $table_data_headers = array(
      0 => array(
        'data' => t('Bean label'),
        'field' => 'label',
        'sort' => 'asc',
      ),
      1 => array(
        'data' => t('Bean title'),
        'field' => 'title',
      ),
      2 => array(
        'data' => t('Bean type'),
        'field' => 'type',
      ),
      3 => array(
        'data' => t('Used in'),
      ),
    );
  }
  else {
    $table_data_headers = array(
      0 => array(
        'data' => t('Used in'),
      ),
    );
  }
  return $table_data_headers;
}

/**
 * Sort bean usage by bean.label
 *
 * @param $a
 * @param $b
 *
 * @return int
 */
function bean_usage_sort_by_label($a, $b) {
  return strcmp($a->label, $b->label);
}

/**
 * Sort bean usage by bean.title
 *
 * @param $a
 * @param $b
 *
 * @return int
 */
function bean_usage_sort_by_title($a, $b) {
  return strcmp($a->title, $b->title);
}

/**
 * Sort bean usage by bean.type
 *
 * @param $a
 * @param $b
 *
 * @return int
 */
function bean_usage_sort_by_type($a, $b) {
  return strcmp($a->type, $b->type);
}

Functions

Namesort descending Description
bean_usage_blockrefence_entity_types Get all of the entity types used with beans via blockreference
bean_usage_blockreference_bundles Get all of the bundles used with beans via blockreference
bean_usage_blockreference_fields Get all fields that are of type blockreference and not deleted
bean_usage_menu Implements hook_menu()
bean_usage_output Displays a table of Beans and their usage
bean_usage_permission Implements hook_permission()
bean_usage_sort_by_label Sort bean usage by bean.label
bean_usage_sort_by_title Sort bean usage by bean.title
bean_usage_sort_by_type Sort bean usage by bean.type
_bean_usage_entity_display Helper function to display an entity on the report
_bean_usage_field_data Get the data from the field_data tables for bean usage based on bean.bid and bean.delta
_bean_usage_table_headers Set the table headers for the table output based on the page that calls for the data.