You are here

function views_field_view_handler_field_view::pre_render in Views Field View 6

Same name and namespace in other branches
  1. 7 views_field_view_handler_field_view.inc \views_field_view_handler_field_view::pre_render()

Run before any fields are rendered.

This gives the handlers some time to set up before any handler has been rendered.

Parameters

$values: An array of all objects returned from the query.

File

./views_field_view_handler_field_view.inc, line 101

Class

views_field_view_handler_field_view

Code

function pre_render($values) {

  // Only act if we are attempting to aggregate all of the field
  // instances into a single query.
  if ($this->options['view'] && $this->options['query_aggregation']) {

    // Note: Unlike render, pre_render will be run exactly once per
    // views_field_view field (not once for each row).
    $child_view_name = $this->options['view'];
    $child_view_display = $this->options['display'];

    // Add each argument token configured for this view_field.
    foreach (explode(',', $this->options['arguments']) as $token) {

      // Remove the brackets around the token
      $argument = substr($token, 1, -1);

      // Collect all of the values that we intend to use as arguments of our single query.
      if (isset($this->view->field[$argument]->field_alias)) {
        $field_alias = $this->view->field[$argument]->field_alias;
        foreach ($values as $value) {
          if (isset($value->{$field_alias})) {
            $this->child_arguments[$field_alias]['argument_name'] = $argument;
            $this->child_arguments[$field_alias]['values'][] = $value->{$field_alias};
          }
        }
      }
    }

    // If we don't have child arguments we should not try to do any of our magic.
    if (count($this->child_arguments)) {

      // Cache the child_view in this object to minize our calls to views_get_view.
      $this->child_view = views_get_view($child_view_name);
      $child_view = $this->child_view;

      // Set the appropriate display.
      $child_view
        ->access($child_view_display);

      // Find the arguments on the child view that we're going to need if the arguments have been overridden.
      foreach ($child_view->display['default']->display_options['arguments'] as $argument_name => $argument_value) {
        if (isset($child_view->display[$child_view_display]->display_options['arguments'][$argument_name])) {
          $configured_arguments[$argument_name] = $child_view->display[$child_view_display]->display_options['arguments'][$argument_name];
        }
        else {
          $configured_arguments[$argument_name] = $child_view->display['default']->display_options['arguments'][$argument_name];
        }
      }
      $argument_ids = array();
      foreach ($this->child_arguments as $child_argument_name => $child_argument) {

        // Work with the arguments on the child view in the order they are
        // specified in our views_field_view field settings.
        $configured_argument = array_shift($configured_arguments);

        // To be able to later split up our results among the appropriate rows,
        // we need to add whatever argument fields we're using to the query.
        $argument_ids[$child_argument_name] = $child_view
          ->add_item($child_view_display, 'field', $configured_argument['table'], $configured_argument['field'], array(
          'exclude' => TRUE,
        ));

        // Initialize the query object so that we have it to alter.
        // The child view may have been limited but our result set here should not be.
        if (isset($child_view->pager['items_per_page'])) {
          $child_view->pager['items_per_page'] = 0;
        }
        $child_view
          ->build();
        $sql = ' IN (';
        $i = 0;
        foreach ($child_argument['values'] as $argument) {

          // TODO: It would be great if this were a bit smarter and if we could
          // use the argument handler to build the sql.  However, this might be
          // irrelevant because any field doing something non-standard would
          // probably not work anyway.
          if ($i > 0) {
            $sql .= ', ';
          }
          $i++;
          if (is_numeric($argument)) {
            $sql .= '%n';
          }
          else {
            $sql .= "'%s'";
          }
        }
        $sql .= ')';

        // Add the WHERE IN clause to this query.
        $child_view->query
          ->add_where(0, $configured_argument['table'] . '.' . $configured_argument['field'] . $sql, $child_argument['values']);
      }
      $child_view->build_info['query'] = $child_view->query
        ->query();
      $child_view->build_info['count_query'] = $child_view->query
        ->query(TRUE);
      $child_view->build_info['query_args'] = $child_view->query
        ->get_where_args();

      // Execute the query to retrieve the results.
      $child_view
        ->execute();

      // Now that the query has run, we need to get the field alias for each argument field
      // so that it can be identified later.
      foreach ($argument_ids as $child_argument_name => $argument_id) {
        $this->child_arguments[$child_argument_name]['child_view_field_alias'] = $child_view->field[$argument_id]->field_alias;
      }
      $results = $child_view->result;

      // Finally: Cache the results so that they're easily accessible for the render function.
      // Loop through the results from the main view so that we can cache the results relevant to each row.
      foreach ($values as $value) {

        // Add an element to the child_view_results array for each of the rows keyed by this view's base_field.
        $this->child_view_results[$value->{$this->view->base_field}] = array();
        $child_view_result_row =& $this->child_view_results[$value->{$this->view->base_field}];

        // Loop through the actual result set looking for matches to these arguments.
        foreach ($results as $result) {

          // Assume that we have a matching item until we know that we don't.
          $matching_item = TRUE;

          // Check each argument that we care about to ensure that it matches.
          foreach ($this->child_arguments as $child_argument_field_alias => $child_argument) {

            // If one of our arguments does not match the argument of this field, do not add it to this row.
            if (isset($value->{$child_argument_field_alias}) && $value->{$child_argument_field_alias} != $result->{$child_argument['child_view_field_alias']}) {
              $matching_item = FALSE;
            }
          }
          if ($matching_item) {
            $child_view_result_row[] = $result;
          }
        }

        // Make a best effort attempt at paging.
        if (isset($this->child_view->pager['items_per_page'])) {
          $item_limit = $this->child_view->pager['items_per_page'];

          // If the item limit exists but is set to zero, do not split up the results.
          if ($item_limit != 0) {
            $results = array_chunk($results, $item_limit);
            $offset = isset($this->child_view->pager['offset']) ? $this->child_view->pager['offset'] : 0;
            $results = $results[$offset];
          }
        }
        unset($child_view_result_row);
      }

      // We have essentially built and executed the child view member of this view.
      // Set it accordingly so that it is not rebuilt during the rendering of each row below.
      $this->child_view->built = TRUE;
      $this->child_view->executed = TRUE;
    }
  }
}