[ Index ]

PHP Cross Reference of Drupal 6 (yi-drupal)

title

Body

[close]

/sites/all/modules/cck/includes/views/handlers/ -> content_handler_field_multiple.inc (source)

   1  <?php
   2  // $Id: content_handler_field_multiple.inc,v 1.1.2.26 2011/01/07 13:33:55 yched Exp $
   3  
   4  /**
   5   * @file
   6   * An extended subclass for field handling that adds multiple field grouping.
   7   *
   8   * Fields that want multiple value grouping options in addition to basic
   9   * field and formatter handling can extend this class.
  10   */
  11  class content_handler_field_multiple extends content_handler_field {
  12    var $defer_query;
  13  
  14    function init(&$view, $options) {
  15      $field = $this->content_field;
  16      parent::init($view, $options);
  17  
  18      $this->defer_query = !empty($options['multiple']['group']) && $field['multiple'];
  19  
  20      if ($this->defer_query) {
  21        // Grouped field: ditch the existing additional_fields (field columns + delta).
  22        // In the main query we'll only need:
  23        // - vid, which will be used to retrieve the actual values in pre_render,
  24        // - node type and nid, which wil be used in the pseudo-node used when
  25        // rendering.
  26        $this->additional_fields = array(
  27          'type' => array('table' => 'node', 'field' => 'type'),
  28          'nid' => array('table' => 'node', 'field' => 'nid'),
  29        );
  30        if ($view->base_table == 'node_revisions') {
  31          $this->additional_fields['vid'] = array('table' => 'node_revisions', 'field' => 'vid');
  32        }
  33        else {
  34          $this->additional_fields['vid'] = array('table' => 'node', 'field' => 'vid');
  35        }
  36      }
  37    }
  38  
  39    function option_definition() {
  40      $options = parent::option_definition();
  41  
  42      $options['multiple'] = array(
  43        'contains' => array(
  44          'group' => array('default' => TRUE),
  45          'multiple_number' => array('default' => ''),
  46          'multiple_from' => array('default' => ''),
  47          'multiple_reversed' => array('default' => FALSE),
  48        ),
  49      );
  50  
  51      return $options;
  52    }
  53  
  54    /**
  55     * Provide 'group multiple values' option.
  56     */
  57    function options_form(&$form, &$form_state) {
  58      parent::options_form($form, $form_state);
  59  
  60      $field = $this->content_field;
  61      $options = $this->options;
  62  
  63      $form['multiple'] = array(
  64        '#access' => $field['multiple'],
  65        '#weight' => 1,
  66      );
  67      $form['multiple']['group'] = array(
  68        '#title' => t('Group multiple values'),
  69        '#type' => 'checkbox',
  70        '#default_value' => $options['multiple']['group'],
  71        '#description' => t('If unchecked, each item in the field will create a new row, which may appear to cause duplicates. This setting is not compatible with click-sorting in table displays.'),
  72      );
  73      // Make the string translatable by keeping it as a whole rather than
  74      // translating prefix and suffix separately.
  75      list($prefix, $suffix) = explode('@count', t('Show @count value(s)'));
  76      $form['multiple']['multiple_number'] = array(
  77        '#type' => 'textfield',
  78        '#size' => 5,
  79        '#field_prefix' => $prefix,
  80        '#field_suffix' => $suffix,
  81        '#default_value' => $options['multiple']['multiple_number'],
  82        '#prefix' => '<div class="container-inline">',
  83        '#process' => array('views_process_dependency'),
  84        '#dependency' => array('edit-options-multiple-group' => array(TRUE)),
  85      );
  86      list($prefix, $suffix) = explode('@count', t('starting from @count'));
  87      $form['multiple']['multiple_from'] = array(
  88        '#type' => 'textfield',
  89        '#size' => 5,
  90        '#field_prefix' => $prefix,
  91        '#field_suffix' => $suffix,
  92        '#default_value' => $options['multiple']['multiple_from'],
  93        '#process' => array('views_process_dependency'),
  94        '#dependency' => array('edit-options-multiple-group' => array(TRUE)),
  95        '#description' => t('(first item is 0)'),
  96      );
  97      $form['multiple']['multiple_reversed'] = array(
  98        '#title' => t('Reversed'),
  99        '#type' => 'checkbox',
 100        '#default_value' => $options['multiple']['multiple_reversed'],
 101        '#suffix' => '</div>',
 102        '#process' => array('views_process_dependency'),
 103        '#dependency' => array('edit-options-multiple-group' => array(TRUE)),
 104        '#description' => t('(start from last values)'),
 105      );
 106    }
 107  
 108    /**
 109     * Determine if this field is click sortable.
 110     */
 111    function click_sortable() {
 112      $field = $this->content_field;
 113      $options = $this->options;
 114  
 115      // Grouped fields are not click-sortable.
 116      return !empty($this->definition['click sortable']) && !$this->defer_query;
 117    }
 118  
 119    function query() {
 120      // If this is not a grouped field, use the generic query().
 121      if (!$this->defer_query) {
 122        return parent::query();
 123      }
 124  
 125      // Grouped field: do NOT call ensure_my_table, only add additional fields.
 126      $this->add_additional_fields();
 127      $this->field_alias = $this->aliases['vid'];
 128    }
 129  
 130    function pre_render($values) {
 131      // If there are no values to render (displaying a summary, or query returned no results),
 132      // or if this is not a grouped field, do nothing specific.
 133      if (isset($this->view->build_info['summary']) || empty($values) || !$this->defer_query) {
 134        return parent::pre_render($values);
 135      }
 136  
 137      $field = $this->content_field;
 138      $db_info = content_database_info($field);
 139      $options = $this->options;
 140  
 141      // Build the list of vids to retrieve.
 142      // TODO: try fetching from cache_content first ??
 143      $vids = array();
 144      $this->field_values = array();
 145      foreach ($values as $result) {
 146        if (isset($result->{$this->field_alias})) {
 147          $vids[] = $result->{$this->field_alias};
 148        }
 149      }
 150  
 151      // It may happend that the multiple values field is related to a non
 152      // required relation for which no node data related to the field being
 153      // processed here is available.
 154      if (empty($vids)) {
 155        return parent::pre_render($values);
 156      }
 157  
 158      // List columns to retrieve.
 159      $alias = content_views_tablename($field);
 160      // Prefix aliases with '_' to avoid clashing with field columns names.
 161      $query_columns = array(
 162        'vid AS _vid',
 163        "delta as _delta",
 164        // nid is needed to generate the links for 'link to node' option.
 165        'nid AS _nid',
 166      );
 167      // The actual field columns.
 168      foreach ($db_info['columns'] as $column => $attributes) {
 169        $query_columns[] = "$attributes[column] AS $column";
 170      }
 171      $query = 'SELECT '. implode(', ', $query_columns) .
 172               ' FROM {'. $db_info['table'] ."}".
 173               " WHERE vid IN (". implode(',', $vids) .')'.
 174               " ORDER BY _nid ASC, _delta ". ($options['multiple']['multiple_reversed'] ? 'DESC' : 'ASC');
 175      $result = db_query($query);
 176  
 177      while ($item = db_fetch_array($result)) {
 178        // Clean up the $item from vid and delta. We keep nid for now.
 179        $vid = $item['_vid'];
 180        unset($item['_vid']);
 181        $delta = !empty($item['_delta']) ? $item['_delta'] : 0;
 182        $item['#delta'] = $item['_delta'];
 183        unset($item['_delta']);
 184        $this->field_values[$vid][$delta] = $item;
 185      }
 186    }
 187  
 188    /**
 189     * Return DIV or SPAN based upon the field's element type.
 190     *
 191     * Fields rendered with the 'group multiple' option use <div> markers,
 192     * and thus shouldn't be wrapped in a <span>.
 193     */
 194    function element_type($none_supported = FALSE, $default_empty = FALSE) {
 195      // If this is not a grouped field, use the parent method.
 196      if (!$this->defer_query) {
 197        return parent::element_type($none_supported, $default_empty);
 198      }
 199  
 200      // The 'element_type' property denotes Views 3.x ('semantic views'
 201      // functionnality). If the property is set, and not set to '' ("default"),
 202      // let the generic method handle the output.
 203      if (isset($this->options['element_type']) && $this->options['element_type'] !== '') {
 204        return parent::element_type($none_supported, $default_empty);
 205      }
 206  
 207      if ($default_empty) {
 208        return '';
 209      }
 210  
 211      if (isset($this->definition['element type'])) {
 212        return $this->definition['element type'];
 213      }
 214  
 215      return 'div';
 216    }
 217  
 218    function render($values) {
 219      // If this is not a grouped field, use content_handler_field::render().
 220      if (!$this->defer_query) {
 221        return parent::render($values);
 222      }
 223  
 224      // We're down to a single node here, so we can retrieve the actual field
 225      // definition for the node type being considered.
 226      $field = content_fields($this->content_field['field_name'], $values->{$this->aliases['type']});
 227  
 228      // If the field does not appear in the node type, then we have no value
 229      // to display, and can just return.
 230      if (empty($field)) {
 231        return '';
 232      }
 233  
 234      $options = $this->options;
 235  
 236      $vid = $values->{$this->field_alias};
 237      if (isset($this->field_values[$vid])) {
 238        // Gather items, respecting the 'Display n values starting from m' settings.
 239        $count_skipped = 0;
 240        $items = array();
 241        foreach ($this->field_values[$vid] as $item) {
 242          if (empty($options['multiple']['multiple_from']) || ($count_skipped >= $options['multiple']['multiple_from'])) {
 243            if (empty($options['multiple']['multiple_number']) || (count($items) < $options['multiple']['multiple_number'])) {
 244              // Grab the nid - needed for render_link().
 245              $nid = $item['_nid'];
 246              unset($item['_nid']);
 247              $items[] = $item;
 248            }
 249            else {
 250              break;
 251            }
 252          }
 253          $count_skipped++;
 254        }
 255  
 256        // Build a pseudo-node from the retrieved values.
 257        $node = drupal_clone($values);
 258        // content_format and formatters will need a 'type'.
 259        $node->type = $values->{$this->aliases['type']};
 260        $node->nid = $values->{$this->aliases['nid']};
 261        $node->vid = $values->{$this->aliases['vid']};
 262  
 263        // Some formatters need to behave differently depending on the build_mode
 264        // (for instance: preview), so we provide one.
 265        $node->build_mode = NODE_BUILD_NORMAL;
 266  
 267        // Render items.
 268        $formatter_name = $options['format'];
 269        if ($items && ($formatter = _content_get_formatter($formatter_name, $field['type']))) {
 270          $rendered = array();
 271          if (content_handle('formatter', 'multiple values', $formatter) == CONTENT_HANDLE_CORE) {
 272            // Single-value formatter.
 273            foreach ($items as $item) {
 274              $output = content_format($field, $item, $formatter_name, $node);
 275              if (!empty($output)) {
 276                $rendered[] = $this->render_link($output, (object) array('nid' => $nid));
 277              }
 278            }
 279          }
 280          else {
 281            // Multiple values formatter.
 282            $output = content_format($field, $items, $formatter_name, $values);
 283            if (!empty($output)) {
 284              $rendered[] = $this->render_link($output, (object) array('nid' => $nid));
 285            }
 286          }
 287  
 288          if (count($rendered) > 1) {
 289            // TODO: could we use generic field display ?
 290            return theme('content_view_multiple_field', $rendered, $field, $values);
 291          }
 292          elseif ($rendered) {
 293            return $rendered[0];
 294          }
 295        }
 296      }
 297  
 298      return '';
 299    }
 300  
 301    function render_link($data, $values) {
 302      if (!$this->defer_query) {
 303        return parent::render_link($data, $values);
 304      }
 305  
 306      if (!empty($this->options['link_to_node']) && $data !== NULL && $data !== '') {
 307        if (method_exists('render_as_link', 'views_handler_field')) {
 308          // Views 2.3+
 309          $this->options['alter']['make_link'] = TRUE;
 310          $this->options['alter']['path'] = "node/" . $values->{$this->aliases['nid']};
 311        }
 312        else {
 313          // Views up to 2.2
 314          return l($data, "node/" . $values->nid, array('html' => TRUE));
 315        }
 316      }
 317      else {
 318        return $data;
 319      }
 320    }
 321  
 322  }


Generated: Mon Jul 9 18:01:44 2012 Cross-referenced by PHPXref 0.7