While views_query::ensure_path() requires a join, it actually continues if it cannot be fetched. $traced gets a key which is an empty string '' which in the second recursion call matches if (isset($traced[$join->left_table])) and returns.

Reading views_query::ensure_table() then reading views_query::ensure_path() also confused me actually. Because the first explicitly checks for a join. The second doesn't so I wan under the impression it doesn't require a join.

Patch attached.

CommentFileSizeAuthor
views_ensure_path_join_check.patch576 bytesAmrMostafa

Comments

merlinofchaos’s picture

Status: Needs review » Fixed

I think this is right.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for two weeks with no activity.

grafsl’s picture

Status: Closed (fixed) » Needs review

Hi,
This patch breaks my views handler.
I define new views_handler_field:

class views_handler_video_thumbnails extends views_handler_field {
  /**
   * Aditional fields to query is added here. This fields are used to generate output.
   */
  function construct() {
    parent::construct();
    $this->additional_fields['nid'] = array('table' => 'node', 'field' => 'nid');
    $this->additional_fields['title'] = array('table' => 'node', 'field' => 'title');
    $this->additional_fields['converted'] = array('table' => 'node', 'field' => 'converted');
    $this->additional_fields['width'] = array('table' => KLIPPS_THUMBNAILS_SIZES_TABLE, 'field' => 'width');
    $this->additional_fields['height'] = array('table' => KLIPPS_THUMBNAILS_SIZES_TABLE, 'field' => 'height');
  }


  /**
   * Add option for thumbnail field in the Views admin UI.
   */
  function option_definition() {
    $options = parent::option_definition();
    $options['type']['sizes'] = variable_get('klipps_thumbnails_default_size', 0);
    return $options;
  }

  /**
   * Options form definition for the Views admin UI.
   *
   * @param $form
   * Form reference.
   *
   * @param $form_state
   * Reference to the array of the form data.
   */
  function options_form(&$form, &$form_state) {
    parent::options_form($form, $form_state);

    $form['type'] = array(
      '#type' => 'fieldset',
      '#collapsible' => FALSE,
      '#title' => t('Thumbnail type'),
      '#description' => t('Select the avaliable thumbnail size.'),
      '#weight' => -10,
      '#tree' => TRUE,
    );

    $info = _klipps_thumbnails_select_all_sizes();
    $options = array();
    if (!empty($info)) {
      foreach ($info as $value) {
        $options[$value['sid']] = $value['title'] . ' ('. $value['width'] .'x'. $value['height'] .')';
      }
    }
    $form['type']['sizes'] = array(
      '#title' => t('Result type'),
      '#type' => 'select',
      '#options' => $options,
      '#default_value' => $this->options['type']['sizes'],
    );
  }


  /**
   * Render thumbnail in the view.
   *
   * @param $values
   * View item which contains thumbnail.
   */
  function render($values) {
    $nid = $values->{$this->aliases['nid']};
    $converted = $values->{$this->aliases['converted']};
    $movie_title = $values->{$this->aliases['title']};
    $show_link = TRUE;
    if ( 0 == $converted ) {
      $show_link = FALSE;
    }
    // Get thumbnail
    $thumbnail = new stdClass();
    $thumbnail->filepath = $values->{$this->field_alias};
    $thumbnail->width = $values->{$this->aliases['width']};
    $thumbnail->height = $values->{$this->aliases['height']};

    $thumbnail_html = theme( "klipps_thumbnails_thumbnail", $thumbnail, $movie_title, $movie_title);


    //Generate link to the movie
    if ($show_link) {
      $options = array( 'html' => TRUE);
      $thumbnail_html = l($thumbnail_html, drupal_get_path_alias('node/'. $nid), $options);
    }
    //return "<div class='thumbnail-wrapper' style='width:". $thumb_size['thumb_width'] ."px;height: ". $thumb_size['thumb_height'] ."px;'>". $thumbnail_html .'</div>';
    return $thumbnail_html;
  }

  /**
   * Ensure the main table for this handler is in the query. We do somewhat
   * debauched things here to allow separate copies of the table to be added
   * for each instance of this field.
   */
  function ensure_my_table() {
    if (!isset($this->table_alias)) {
      //Add thumbnails table
      $join_extra[] = array('field' => 'sid', 'value' => $this->options['type']['sizes'], 'numeric' => TRUE);
      $alias = $this->table;
      $alias .= '_'. $this->options['type']['sizes'];

      if (empty($alias)) {
        $alias = NULL;
      }

      $join = new views_join();
      $join->construct($this->table, 'movie_upload', 'fid', 'fid', $join_extra);


      if ($table_alias = $this->query->add_table($this->table, $this->relationship, $join, $alias)) {
        if ($table_alias === TRUE) {
          $this->table_alias = $alias;
        }
        else {
          $this->table_alias = $table_alias;
        }
      }
      //Add thumbnail sizes table
      $alias_size = KLIPPS_THUMBNAILS_SIZES_TABLE;
      $alias_size .= '_'. $this->options['type']['sizes'];
      $join = new views_join();
      $join->construct(KLIPPS_THUMBNAILS_SIZES_TABLE, $this->table_alias, 'sid', 'sid');
      $this->query->add_table(KLIPPS_THUMBNAILS_SIZES_TABLE, NULL, $join, $alias_size);
    }
    return $this->table_alias;
  }
}

I use this handler on Attachment View.
Without this patch View build this query:

SELECT klipps_categories.k_cid AS k_cid,
   thumbnails_1.filepath AS thumbnails_1_filepath,
   node.nid AS node_nid,
   node.title AS node_title,
   node.converted AS node_converted,
   thumbnail_sizes_1.width AS thumbnail_sizes_1_width,
   thumbnail_sizes_1.height AS thumbnail_sizes_1_height,
   users.name AS users_name,
   users.uid AS users_uid,
   klipps_statistics.weekcount AS klipps_statistics_weekcount
 FROM klipps_categories klipps_categories 
 LEFT JOIN klipps_categories_node klipps_categories_node ON klipps_categories.k_cid = klipps_categories_node.k_cid
 LEFT JOIN node node ON klipps_categories_node.nid = node.nid
 LEFT JOIN movie_upload movie_upload ON node.nid = movie_upload.nid
 LEFT JOIN thumbnails thumbnails_1 ON movie_upload.fid = thumbnails_1.fid AND thumbnails_1.sid = 1
 LEFT JOIN thumbnail_sizes thumbnail_sizes_1 ON thumbnails_1.sid = thumbnail_sizes_1.sid
 INNER JOIN users users ON node.uid = users.uid
 LEFT JOIN klipps_statistics klipps_statistics ON node.nid = klipps_statistics.nid
 WHERE (node.type in ('movie')) AND (node.converted <> 0) AND (node.status <> 0) AND (klipps_categories.k_cid = 4)
   ORDER BY klipps_statistics_weekcount DESC

After implementing patch :

SELECT klipps_categories.k_cid AS k_cid,
   thumbnails_1.filepath AS thumbnails_1_filepath,
   node.nid AS node_nid,
   node.title AS node_title,
   node.converted AS node_converted,
   width,
   height,
   users.name AS users_name,
   users.uid AS users_uid,
   node.created AS node_created
 FROM klipps_categories klipps_categories 
 LEFT JOIN klipps_categories_node klipps_categories_node ON klipps_categories.k_cid = klipps_categories_node.k_cid
 LEFT JOIN node node ON klipps_categories_node.nid = node.nid
 LEFT JOIN movie_upload movie_upload ON node.nid = movie_upload.nid
 LEFT JOIN thumbnails thumbnails_1 ON movie_upload.fid = thumbnails_1.fid AND thumbnails_1.sid = 1
 INNER JOIN users users ON node.uid = users.uid
 WHERE (node.type in ('movie')) AND (node.converted <> 0) AND (node.status <> 0) AND (klipps_categories.k_cid = 3)
   ORDER BY node_created DESC

One join statement is missing:

LEFT JOIN thumbnail_sizes thumbnail_sizes_1 ON thumbnails_1.sid = thumbnail_sizes_1.sid

and two unknown fields in SELECT phase: width and height.

P.S. In Page View this handler works fine.

AmrMostafa’s picture

My views2 is too rusty at the moment to be able to produce something like what your code does. If someone can help me reproduce the same issue, I will work on it.

merlinofchaos’s picture

Status: Needs review » Active

This is too complex for me to understand what's going on here. Also not a patch so 'needs review' is the wrong status.

esmerel’s picture

Status: Active » Closed (fixed)

Given the age of this issue, I have hope that it's resolved or no longer relevant.